diff --git a/associate.m b/associate.m index 423d58f..3c6767b 100644 --- a/associate.m +++ b/associate.m @@ -51,6 +51,11 @@ struct reference_list * @syncronize(). */ mutex_t lock; + /** + * Garbage collection type. This stores the location of all of the + * instance variables in the object that may contain pointers. + */ + void *gc_type; /** * Array of references. */ @@ -310,6 +315,17 @@ void objc_removeAssociatedObjects(id object) cleanupReferenceList(referenceListForObject(object, NO)); } +PRIVATE void *gc_typeForClass(Class cls) +{ + struct reference_list *list = referenceListForObject(cls, YES); + return list->gc_type; +} +PRIVATE void gc_setTypeForClass(Class cls, void *type) +{ + struct reference_list *list = referenceListForObject(cls, YES); + list->gc_type = type; +} + int objc_sync_enter(id object) { struct reference_list *list = referenceListForObject(object, YES); diff --git a/class.h b/class.h index a827f30..56f48bf 100644 --- a/class.h +++ b/class.h @@ -1,6 +1,5 @@ #ifndef __OBJC_CLASS_H_INCLUDED #define __OBJC_CLASS_H_INCLUDED -#ifndef __objc_runtime_INCLUDE_GNU struct objc_class { /** @@ -134,7 +133,6 @@ struct legacy_abi_objc_class void *gc_object_type; }; -#endif /** * An enumerated type describing all of the valid flags that may be used in the diff --git a/gc_boehm.c b/gc_boehm.c index bd7444a..d14b8d0 100644 --- a/gc_boehm.c +++ b/gc_boehm.c @@ -1,4 +1,7 @@ #include "objc/runtime.h" +#include "class.h" +#include "ivar.h" +#include "lock.h" #include "objc/objc-auto.h" #include "visibility.h" #include @@ -13,6 +16,9 @@ #define __sync_swap __sync_lock_test_and_set #endif +GC_descr gc_typeForClass(Class cls); +void gc_setTypeForClass(Class cls, GC_descr type); + static unsigned long collectionType(unsigned options) { // Low 2 bits in GC options are used for the @@ -112,9 +118,11 @@ id objc_assign_strongCast(id val, id *ptr) id objc_assign_global(id val, id *ptr) { + GC_add_roots(ptr, ptr+1); *ptr = val; return val; } + id objc_assign_ivar(id val, id dest, ptrdiff_t offset) { GC_change_stubborn(dest); @@ -184,9 +192,58 @@ static void runFinalize(void *addr, void *context) objc_msg_lookup(addr, finalize)(addr, finalize); } +static void collectIvarForClass(Class cls, GC_word *bitmap) +{ + for (unsigned i=0 ; iivars->count ; i++) + { + struct objc_ivar *ivar = &cls->ivars->ivar_list[i]; + size_t start = ivar->offset; + size_t end = i+1 < cls->ivars->count ? cls->ivars->ivar_list[i+1].offset + : cls->instance_size; + switch (ivar->type[0]) + { + // Explicit pointer types + case '^': case '@': + // We treat collections as pointer types for now, because people + // tend to do ugly things with them (especially unions!). + case '[': case '{': case '(': + for (unsigned b=(start / sizeof(void*)) ; b<(end/sizeof(void*)) ; b++) + { + GC_set_bit(bitmap, b); + } + } + } + if (cls->super_class) + { + collectIvarForClass(cls->super_class, bitmap); + } +} + +static GC_descr descriptor_for_class(Class cls) +{ + GC_descr descr = gc_typeForClass(cls); + + if (0 != descr) { return descr; } + + LOCK_RUNTIME_FOR_SCOPE(); + + descr = (GC_descr)gc_typeForClass(cls); + if (0 != descr) { return descr; } + + size_t size = cls->instance_size / 8 + 1; + GC_word bitmap[size]; + memset(bitmap, 0, size); + collectIvarForClass(cls, bitmap); + descr = GC_make_descriptor(bitmap, cls->instance_size); + gc_setTypeForClass(cls, descr); + return descr; +} + static id allocate_class(Class cls, size_t extra) { id obj; + // If there are some extra bytes, they may contain pointers, so we ignore + // the type if (extra > 0) { // FIXME: Overflow checking! @@ -194,7 +251,8 @@ static id allocate_class(Class cls, size_t extra) } else { - obj = GC_malloc_stubborn(class_getInstanceSize(cls)); + GC_descr d = descriptor_for_class(cls); + obj = GC_malloc_explicitly_typed(class_getInstanceSize(cls), d); } GC_register_finalizer_no_order(obj, runFinalize, 0, 0, 0); return obj; @@ -340,6 +398,7 @@ static void init(void) refcounts = refcount_create(4096); GC_word bitmap = 0; UnscannedDescr = GC_make_descriptor(&bitmap, 1); + GC_clear_roots(); } BOOL objc_collecting_enabled(void) diff --git a/objc/objc-auto.h b/objc/objc-auto.h index 405ff16..42f1c80 100644 --- a/objc/objc-auto.h +++ b/objc/objc-auto.h @@ -173,7 +173,8 @@ void objc_registerThreadWithCollector(void); void objc_unregisterThreadWithCollector(void); /** * Registers the current thread with the garbage collector and aborts if the - * registration failed. + * registration failed. The thread is expected to have already been + * registered. This will print a warning message if it has not been. */ void objc_assertRegisteredThreadWithCollector();