Permalink
Browse files

some work on garbage collecting singleton classes - disabled for now …

…since it breaks rubyspec
  • Loading branch information...
1 parent 125dc53 commit c1833dd1d2764711f3ea658d7e1108e62057dddb Laurent Sansonetti committed Jun 13, 2011
Showing with 238 additions and 201 deletions.
  1. +0 −11 NSArray.m
  2. +0 −11 NSDictionary.m
  3. +0 −11 NSString.m
  4. +0 −18 array.c
  5. +103 −84 class.c
  6. +16 −0 class.h
  7. +3 −2 gc.c
  8. +7 −16 hash.c
  9. +2 −1 id.c
  10. +2 −0 id.h
  11. +2 −0 inits.c
  12. +40 −30 object.c
  13. +0 −13 string.c
  14. +59 −4 vm.cpp
  15. +4 −0 vm.h
View
@@ -50,16 +50,6 @@
return dup;
}
-static id
-nsary_clone(id rcv, SEL sel)
-{
- id clone = nsary_dup(rcv, 0);
- if (OBJ_FROZEN(rcv)) {
- OBJ_FREEZE(clone);
- }
- return clone;
-}
-
static id
nsary_clear(id rcv, SEL sel)
{
@@ -1000,7 +990,6 @@
rb_include_module(rb_cArray, rb_mEnumerable);
rb_objc_define_method(rb_cArray, "dup", nsary_dup, 0);
- rb_objc_define_method(rb_cArray, "clone", nsary_clone, 0);
rb_objc_define_method(rb_cArray, "clear", nsary_clear, 0);
rb_objc_define_method(rb_cArray, "to_s", nsary_inspect, 0);
rb_objc_define_method(rb_cArray, "inspect", nsary_inspect, 0);
View
@@ -55,16 +55,6 @@
return dup;
}
-static id
-nshash_clone(id rcv, SEL sel)
-{
- id clone = nshash_dup(rcv, 0);
- if (OBJ_FROZEN(rcv)) {
- OBJ_FREEZE(clone);
- }
- return clone;
-}
-
static id
nshash_rehash(id rcv, SEL sel)
{
@@ -475,7 +465,6 @@
rb_include_module(rb_cHash, rb_mEnumerable);
rb_objc_define_method(rb_cHash, "dup", nshash_dup, 0);
- rb_objc_define_method(rb_cHash, "clone", nshash_clone, 0);
rb_objc_define_method(rb_cHash, "rehash", nshash_rehash, 0);
rb_objc_define_method(rb_cHash, "to_hash", nshash_to_hash, 0);
rb_objc_define_method(rb_cHash, "to_a", nshash_to_a, 0);
View
@@ -61,16 +61,6 @@
return dup;
}
-static id
-nsstr_clone(id rcv, SEL sel)
-{
- id clone = nsstr_dup(rcv, 0);
- if (OBJ_FROZEN(rcv)) {
- OBJ_FREEZE(clone);
- }
- return clone;
-}
-
static id
nsstr_to_s(id rcv, SEL sel)
{
@@ -286,7 +276,6 @@
assert(rb_cNSMutableString != 0);
rb_objc_define_method(rb_cString, "dup", nsstr_dup, 0);
- rb_objc_define_method(rb_cString, "clone", nsstr_clone, 0);
rb_objc_define_method(rb_cString, "to_s", nsstr_to_s, 0);
rb_objc_define_method(rb_cString, "to_str", nsstr_to_s, 0);
rb_objc_define_method(rb_cString, "replace", nsstr_replace, 1);
View
18 array.c
@@ -1194,23 +1194,6 @@ rary_dup(VALUE ary, SEL sel)
return dup;
}
-static VALUE
-rary_clone(VALUE ary, SEL sel)
-{
- VALUE clone = rary_copy(ary, CLASS_OF(ary));
-
- if (OBJ_TAINTED(ary)) {
- OBJ_TAINT(clone);
- }
- if (OBJ_UNTRUSTED(ary)) {
- OBJ_UNTRUST(clone);
- }
- if (OBJ_FROZEN(ary)) {
- OBJ_FREEZE(clone);
- }
- return clone;
-}
-
/*
* call-seq:
* array.join(sep=$,) -> str
@@ -3761,7 +3744,6 @@ Init_Array(void)
rb_objc_define_method(rb_cRubyArray, "initialize_copy", rary_replace, 1);
rb_objc_define_method(rb_cRubyArray, "to_a", rary_to_a, 0);
rb_objc_define_method(rb_cRubyArray, "dup", rary_dup, 0);
- rb_objc_define_method(rb_cRubyArray, "clone", rary_clone, 0);
rb_objc_define_method(rb_cRubyArray, "to_s", rary_inspect, 0);
rb_objc_define_method(rb_cRubyArray, "inspect", rary_inspect, 0);
rb_objc_define_method(rb_cRubyArray, "==", rary_equal, 1);
View
187 class.c
@@ -27,7 +27,7 @@ extern VALUE rb_cModuleObject;
static bool
rb_class_hidden(VALUE klass)
{
- return klass == rb_cModuleObject || RCLASS_SINGLETON(klass);
+ return klass == rb_cModuleObject || klass == rb_cRubyObject || RCLASS_SINGLETON(klass);
}
VALUE
@@ -344,60 +344,90 @@ rb_singleton_class_clone(VALUE obj)
if (!RCLASS_SINGLETON(klass)) {
return klass;
}
- else {
- /* copy singleton(unnamed) class */
- VALUE clone = rb_objc_create_class(NULL, RCLASS_SUPER(klass));
- CFMutableDictionaryRef ivar_dict = rb_class_ivar_dict(klass);
- if (ivar_dict != NULL) {
- CFMutableDictionaryRef cloned_ivar_dict;
+ // Create new singleton class.
+ VALUE clone = rb_objc_create_class(NULL, RCLASS_SUPER(klass));
- cloned_ivar_dict = CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)ivar_dict);
- rb_class_ivar_set_dict(clone, cloned_ivar_dict);
- CFMakeCollectable(cloned_ivar_dict);
- }
+ // Copy ivars.
+ CFMutableDictionaryRef ivar_dict = rb_class_ivar_dict(klass);
+ if (ivar_dict != NULL) {
+ CFMutableDictionaryRef cloned_ivar_dict =
+ CFDictionaryCreateMutableCopy(NULL, 0, (CFDictionaryRef)ivar_dict);
+ rb_class_ivar_set_dict(clone, cloned_ivar_dict);
+ CFMakeCollectable(cloned_ivar_dict);
+ }
- Method *methods;
- unsigned i, methods_count;
- methods = class_copyMethodList((Class)klass, &methods_count);
- if (methods != NULL) {
- for (i = 0; i < methods_count; i++) {
- Method method = methods[i], method2;
- method2 = class_getInstanceMethod((Class)clone, method_getName(method));
- if (method2 != class_getInstanceMethod((Class)RCLASS_SUPER(clone), method_getName(method))) {
- method_setImplementation(method2, method_getImplementation(method));
- }
- else {
- assert(class_addMethod((Class)clone,
- method_getName(method),
- method_getImplementation(method),
- method_getTypeEncoding(method)));
- }
- }
- free(methods);
- }
+ // Copy methods.
+ rb_vm_copy_methods((Class)klass, (Class)clone);
+
+ rb_singleton_class_attached(clone, obj);
+ if (RCLASS_SUPER(clone) == rb_cRubyObject) {
+ long v = RCLASS_VERSION(clone) ^ RCLASS_IS_OBJECT_SUBCLASS;
+ RCLASS_SET_VERSION(clone, v);
+ }
+ RCLASS_SET_VERSION_FLAG(clone, RCLASS_IS_SINGLETON);
+ return clone;
+}
- rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
- if (RCLASS_SUPER(clone) == rb_cRubyObject) {
- long v = RCLASS_VERSION(clone) ^ RCLASS_IS_OBJECT_SUBCLASS;
- RCLASS_SET_VERSION(clone, v);
+static void
+robj_sclass_finalize_imp(void *rcv, SEL sel)
+{
+ bool changed = false;
+ while (true) {
+ VALUE k = *(VALUE *)rcv;
+ if (!RCLASS_SINGLETON(k)
+ || !rb_singleton_class_attached_object(k) == (VALUE)rcv) {
+ break;
}
- RCLASS_SET_VERSION_FLAG(clone, RCLASS_IS_SINGLETON);
+ VALUE sk = RCLASS_SUPER(k);
+ if (sk == 0) {
+ // This can't happen, but we are never sure...
+ break;
+ }
+ *(VALUE *)rcv = sk;
+
+ rb_vm_dispose_class((Class)k);
+
+ changed = true;
+ }
- return clone;
+#if 0
+ if (changed) {
+ objc_msgSend(rcv, selFinalize);
}
+#endif
+}
+
+void
+rb_singleton_class_promote_for_gc(VALUE klass)
+{
+ rb_objc_install_method2((Class)klass, "finalize",
+ (IMP)robj_sclass_finalize_imp);
}
void
rb_singleton_class_attached(VALUE klass, VALUE obj)
{
if (RCLASS_SINGLETON(klass)) {
- static ID attachedId = 0;
- if (attachedId == 0) {
- attachedId = rb_intern("__attached__");
+ // Weak ref.
+ VALUE wobj = LONG2NUM((long)obj);
+ rb_ivar_set(klass, idAttached, wobj);
+ // FIXME commented for now as it breaks some RubySpecs.
+ //rb_singleton_class_promote_for_gc(klass);
+ }
+}
+
+VALUE
+rb_singleton_class_attached_object(VALUE klass)
+{
+ if (RCLASS_SINGLETON(klass)) {
+ // Weak ref.
+ VALUE obj = rb_ivar_get(klass, idAttached);
+ if (FIXNUM_P(obj)) {
+ return (VALUE)NUM2LONG(obj);
}
- rb_ivar_set(klass, attachedId, obj);
}
+ return Qnil;
}
VALUE
@@ -417,16 +447,24 @@ rb_make_singleton_class(VALUE super)
VALUE
rb_make_metaclass(VALUE obj, VALUE super)
{
+ VALUE klass;
if (TYPE(obj) == T_CLASS && RCLASS_SINGLETON(obj)) {
RBASIC(obj)->klass = rb_cClass;
- return rb_cClass;
+ klass = rb_cClass;
}
else {
- VALUE klass = rb_make_singleton_class(super);
- RBASIC(obj)->klass = klass;
- rb_singleton_class_attached(klass, obj);
- return klass;
+ VALUE objk = RBASIC(obj)->klass;
+ if (RCLASS_SINGLETON(objk)
+ && rb_singleton_class_attached_object(objk) == obj) {
+ klass = objk;
+ }
+ else {
+ klass = rb_make_singleton_class(super);
+ RBASIC(obj)->klass = klass;
+ rb_singleton_class_attached(klass, obj);
+ }
}
+ return klass;
}
VALUE
@@ -1115,8 +1153,6 @@ rb_undef_method(VALUE klass, const char *name)
VALUE
rb_singleton_class(VALUE obj)
{
- VALUE klass;
-
if (FIXNUM_P(obj) || SYMBOL_P(obj) || FIXFLOAT_P(obj)) {
rb_raise(rb_eTypeError, "can't define singleton");
}
@@ -1127,45 +1163,18 @@ rb_singleton_class(VALUE obj)
rb_bug("unknown immediate %ld", obj);
}
-#if 0
- DEFER_INTS;
- if (RCLASS_SINGLETON(RBASIC(obj)->klass) &&
- rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) {
- klass = RBASIC(obj)->klass;
- }
- else
-#endif
- {
- switch (TYPE(obj)) {
- case T_CLASS:
- case T_MODULE:
- klass = *(VALUE *)obj;
- break;
+ VALUE klass;
+ switch (TYPE(obj)) {
+ case T_CLASS:
+ case T_MODULE:
+ // FIXME we should really create a new metaclass here.
+ klass = *(VALUE *)obj;
+ break;
- default:
- if (RCLASS_SINGLETON(RBASIC(obj)->klass) &&
- rb_iv_get(RBASIC(obj)->klass, "__attached__") == obj) {
- klass = RBASIC(obj)->klass;
- }
- else {
- klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
- }
- break;
- }
- }
-#if 0
- if (OBJ_TAINTED(obj)) {
- OBJ_TAINT(klass);
- }
- else {
- OBJ_UNTAINT(klass);
- }
- if (OBJ_FROZEN(obj)) {
- OBJ_FREEZE(klass);
+ default:
+ klass = rb_make_metaclass(obj, RBASIC(obj)->klass);
+ break;
}
-#endif
-// ALLOW_INTS;
-
return klass;
}
@@ -1292,6 +1301,16 @@ Init_PreClass(void)
assert(rb_class_flags != NULL);
}
+void
+Init_Class(void)
+{
+#if 0
+ rb_cSClassFinalizer = rb_define_class("__SClassFinalizer", rb_cObject);
+ sclass_finalize_imp_super = rb_objc_install_method2(
+ (Class)rb_cSClassFinalizer, "finalize", (IMP)sclass_finalize_imp);
+#endif
+}
+
static int
foundation_type(Class k)
{
View
16 class.h
@@ -20,6 +20,8 @@ void rb_objc_class_sync_version(Class klass, Class super_class);
void rb_define_object_special_methods(VALUE klass);
VALUE rb_class_new_instance_imp(VALUE, SEL, int, VALUE *);
VALUE rb_make_singleton_class(VALUE super);
+VALUE rb_singleton_class_attached_object(VALUE klass);
+void rb_singleton_class_promote_for_gc(VALUE klass);
#define RCLASS_IS_OBJECT_SUBCLASS (1<<1) /* class is a true RubyObject subclass */
#define RCLASS_IS_RUBY_CLASS (1<<2) /* class was created from Ruby */
@@ -63,6 +65,20 @@ rb_class_get_mask(Class k)
return 0;
}
+static inline bool
+rb_class_erase_mask(Class k)
+{
+ rb_class_flags_cache_t *e = &rb_class_flags[rb_class_flags_hash(k)];
+ while (e != NULL) {
+ if (e->klass == k) {
+ e->klass = 0;
+ return true;
+ }
+ e = e->next;
+ }
+ return false;
+}
+
static inline void
rb_class_set_mask(Class k, unsigned long mask)
{
View
5 gc.c
@@ -1066,8 +1066,9 @@ print_memory_object(task_t task, void *context, unsigned type_mask,
for (vm_range_t *r = ranges, *end = ranges + range_count; r < end; r++) {
const size_t size = auto_zone_size(__auto_zone, (void *)r->address);
if (size >= min_size) {
- printf("address %p size %ld layout type ",
- (void *)r->address, size);
+ printf("address %p size %ld rc %d layout type ",
+ (void *)r->address, size,
+ auto_zone_retain_count(__auto_zone, (void *)r->address));
switch (auto_zone_get_layout_type(__auto_zone,
(void *)r->address)) {
case AUTO_OBJECT:
Oops, something went wrong.

0 comments on commit c1833dd

Please sign in to comment.