You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
146 lines
3.6 KiB
Objective-C
146 lines
3.6 KiB
Objective-C
#include "../objc/objc-api.h"
|
|
#include "../objc/runtime.h"
|
|
#import "visit.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
/**
|
|
* Structure storing information about object children.
|
|
*
|
|
* Note: This structure is quite inefficient. We can optimise it a lot later,
|
|
* if required.
|
|
*/
|
|
struct GCChildInfo
|
|
{
|
|
/** Number of children of this class. */
|
|
unsigned int count;
|
|
/** Offsets of children. */
|
|
size_t *offsets;
|
|
/** Method pointer for enumerating extra children. */
|
|
IMP extraChildren;
|
|
};
|
|
|
|
@interface NSObject
|
|
- (BOOL)instancesRespondToSelector: (SEL)aSel;
|
|
- (IMP)instanceMethodForSelector: (SEL)aSel;
|
|
- (void)_visitChildrenWithFunction: (visit_function_t)function
|
|
context: (void*)context
|
|
visitWeak: (BOOL)aFlag;
|
|
@end
|
|
static SEL visitSelector = @selector(_visitChildrenWithFunction:context:visitWeak:);
|
|
|
|
/**
|
|
* Macro for adding an offset to the offset buffer and resizing it if required.
|
|
*/
|
|
#define ADD_OFFSET(offset) \
|
|
do {\
|
|
if (found == space)\
|
|
{\
|
|
space *= 2;\
|
|
buffer = realloc(buffer, sizeof(size_t[space]));\
|
|
}\
|
|
buffer[found++] = offset;\
|
|
} while(0)
|
|
|
|
// Note: If we want to save space we could use char*s and short*s for objects
|
|
// less than 2^8 and 2^16 big and add a header indicating this.
|
|
/**
|
|
* Create an instance variable map for the specified class. Inspects the ivars
|
|
* metadata and creates a GCChildInfo structure for the class. This is cached
|
|
* in the gc_object_type field in the class structure.
|
|
*
|
|
* FIXME: This is a hack. The compiler should generate this stuff, not the
|
|
* runtime.
|
|
*/
|
|
struct GCChildInfo *GCMakeIVarMap(Class aClass)
|
|
{
|
|
struct GCChildInfo *info = calloc(1, sizeof(struct GCChildInfo));
|
|
|
|
unsigned int ivarCount;
|
|
Ivar *ivars = class_copyIvarList(aClass, &ivarCount);
|
|
|
|
if (0 == ivarCount)
|
|
{
|
|
info->count = 0;
|
|
info->offsets = NULL;
|
|
}
|
|
else
|
|
{
|
|
unsigned found = 0;
|
|
// First guess - every instance variable is an object
|
|
size_t space = sizeof(size_t[ivarCount]);
|
|
size_t *buffer = malloc(space);
|
|
|
|
for (unsigned i=0 ; i<ivarCount ; ++i)
|
|
{
|
|
Ivar ivar = ivars[i];
|
|
const char *type = ivar_getTypeEncoding(ivar);
|
|
switch(type[0])
|
|
{
|
|
case '@':
|
|
{
|
|
// If it's an object, add it to the list.
|
|
// FIXME: Weak ivars
|
|
ADD_OFFSET(ivar_getOffset(ivar));
|
|
break;
|
|
}
|
|
case '[':
|
|
case '{':
|
|
{
|
|
if (strchr(type, '@'))
|
|
{
|
|
//FIXME: Parse structures and arrays correctly
|
|
fprintf(stderr, "Compound type found in class %s, type: %s is "
|
|
"incorrectly handled", class_getName(aClass),
|
|
ivar_getTypeEncoding(ivar));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
info->count = found;
|
|
info->offsets = realloc(buffer, sizeof(size_t[found]));
|
|
}
|
|
/* FIXME: Use the runtime functions for this
|
|
if ([aClass instancesRespondToSelector: visitSelector])
|
|
{
|
|
info->extraChildren =
|
|
[aClass instanceMethodForSelector: visitSelector];
|
|
}
|
|
*/
|
|
aClass->gc_object_type = info;
|
|
return info;
|
|
}
|
|
|
|
void GCVisitChildren(id object, visit_function_t function, void *argument,
|
|
BOOL visitWeakChildren)
|
|
{
|
|
Class cls = object->class_pointer;
|
|
while (Nil != cls)
|
|
{
|
|
if (NULL == cls->gc_object_type)
|
|
{
|
|
// FIXME: Locking
|
|
GCMakeIVarMap(cls);
|
|
}
|
|
struct GCChildInfo *info = cls->gc_object_type;
|
|
for (unsigned i=0 ; i<info->count ; ++i)
|
|
{
|
|
id child = *(id*)(((char*)object) + info->offsets[i]);
|
|
if (child != nil)
|
|
{
|
|
BOOL isWeak = (intptr_t)child & 1;
|
|
function(object, argument, isWeak);
|
|
}
|
|
}
|
|
if (NULL != info->extraChildren)
|
|
{
|
|
info->extraChildren(object, visitSelector, function, argument,
|
|
visitWeakChildren);
|
|
}
|
|
cls = cls->super_class;
|
|
}
|
|
}
|