Skip to content

Commit

Permalink
some work on garbage collecting singleton classes - disabled for now …
Browse files Browse the repository at this point in the history
…since it breaks rubyspec
  • Loading branch information
Laurent Sansonetti committed Jun 13, 2011
1 parent 125dc53 commit c1833dd
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 201 deletions.
11 changes: 0 additions & 11 deletions NSArray.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 0 additions & 11 deletions NSDictionary.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 0 additions & 11 deletions NSString.m
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 0 additions & 18 deletions array.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
187 changes: 103 additions & 84 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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");
}
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
{
Expand Down
16 changes: 16 additions & 0 deletions class.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand Down
5 changes: 3 additions & 2 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading

0 comments on commit c1833dd

Please sign in to comment.