Navigation Menu

Skip to content

Commit

Permalink
remove the ugly & evil code that was automatically inserting special …
Browse files Browse the repository at this point in the history
…objective-c primitive methods when subclassing NSArray/String/Dictionary from ruby, with the new architecture it's unlikely to happen anymore

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3954 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information
lrz committed Apr 22, 2010
1 parent c306298 commit 2aae14f
Show file tree
Hide file tree
Showing 13 changed files with 41 additions and 368 deletions.
114 changes: 0 additions & 114 deletions NSArray.m
Expand Up @@ -17,7 +17,6 @@
VALUE rb_cArray;
VALUE rb_cNSArray;
VALUE rb_cNSMutableArray;
static VALUE rb_cCFArray;

static id
nsary_dup(id rcv, SEL sel)
Expand Down Expand Up @@ -939,12 +938,6 @@
void
Init_NSArray(void)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
rb_cCFArray = (VALUE)objc_getClass("NSCFArray");
#else
rb_cCFArray = (VALUE)objc_getClass("__NSCFArray");
#endif
assert(rb_cCFArray != 0);
rb_cNSArray = (VALUE)objc_getClass("NSArray");
assert(rb_cNSArray != 0);
rb_cArray = rb_cNSArray;
Expand Down Expand Up @@ -1036,113 +1029,6 @@
rb_objc_define_method(rb_cArray, "sample", rary_sample, -1);
}

#define PREPARE_RCV(x) \
Class old = *(Class *)x; \
*(Class *)x = (Class)rb_cCFArray;

#define RESTORE_RCV(x) \
*(Class *)x = old;

static long
imp_rb_array_count(id rcv, SEL sel)
{
PREPARE_RCV(rcv);
const long count = [rcv count];
RESTORE_RCV(rcv);
return count;
}

static id
imp_rb_array_objectAtIndex(id rcv, SEL sel, long idx)
{
PREPARE_RCV(rcv);
id obj = [rcv objectAtIndex:idx];
RESTORE_RCV(rcv);
return obj;
}

static void
imp_rb_array_insertObjectAtIndex(id rcv, SEL sel, id obj, long idx)
{
PREPARE_RCV(rcv);
[rcv insertObject:obj atIndex:idx];
RESTORE_RCV(rcv);
}

static void
imp_rb_array_removeObjectAtIndex(id rcv, SEL sel, long idx)
{
PREPARE_RCV(rcv);
[rcv removeObjectAtIndex:idx];
RESTORE_RCV(rcv);
}

static void
imp_rb_array_replaceObjectAtIndexWithObject(id rcv, SEL sel, long idx, id obj)
{
PREPARE_RCV(rcv);
[rcv replaceObjectAtIndex:idx withObject:obj];
RESTORE_RCV(rcv);
}

static void
imp_rb_array_addObject(id rcv, SEL sel, id obj)
{
PREPARE_RCV(rcv);
[rcv addObject:obj];
RESTORE_RCV(rcv);
}

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
// This is to work around a bug where CF will try to call an non-existing
// method.
static CFIndex
imp_rb_array_cfindexOfObjectInRange(void *rcv, SEL sel, void *obj,
CFRange range)
{
CFIndex i;
PREPARE_RCV(rcv);
i = CFArrayGetFirstIndexOfValue((CFArrayRef)rcv, range, obj);
RESTORE_RCV(rcv);
return i;
}
#endif

void
rb_objc_install_array_primitives(Class klass)
{
rb_objc_install_method2(klass, "count", (IMP)imp_rb_array_count);
rb_objc_install_method2(klass, "objectAtIndex:",
(IMP)imp_rb_array_objectAtIndex);

const bool is_mutable = class_getSuperclass(klass)
== (Class)rb_cNSMutableArray;

if (is_mutable) {
rb_objc_install_method2(klass, "insertObject:atIndex:",
(IMP)imp_rb_array_insertObjectAtIndex);
rb_objc_install_method2(klass, "removeObjectAtIndex:",
(IMP)imp_rb_array_removeObjectAtIndex);
rb_objc_install_method2(klass, "replaceObjectAtIndex:withObject:",
(IMP)imp_rb_array_replaceObjectAtIndexWithObject);
rb_objc_install_method2(klass, "addObject:",
(IMP)imp_rb_array_addObject);
}

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
// This is to work around a bug where CF will try to call an non-existing
// method.
rb_objc_install_method2(klass, "_cfindexOfObject:range:",
(IMP)imp_rb_array_cfindexOfObjectInRange);
Method m = class_getInstanceMethod(klass,
sel_registerName("_cfindexOfObject:range:"));
class_addMethod(klass, sel_registerName("_cfindexOfObject:inRange:"),
method_getImplementation(m), method_getTypeEncoding(m));
#endif

//rb_objc_define_method(*(VALUE *)klass, "alloc", ary_alloc, 0);
}

// MRI compatibility API.

VALUE
Expand Down
122 changes: 0 additions & 122 deletions NSDictionary.m
Expand Up @@ -17,7 +17,6 @@
VALUE rb_cHash;
VALUE rb_cNSHash;
VALUE rb_cNSMutableHash;
static VALUE rb_cCFHash;

static id
to_hash(id hash)
Expand Down Expand Up @@ -436,12 +435,6 @@
void
Init_NSDictionary(void)
{
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
rb_cCFHash = (VALUE)objc_getClass("NSCFDictionary");
#else
rb_cCFHash = (VALUE)objc_getClass("__NSCFDictionary");
#endif
assert(rb_cCFHash != 0);
rb_cNSHash = (VALUE)objc_getClass("NSDictionary");
assert(rb_cNSHash != 0);
rb_cHash = rb_cNSHash;
Expand Down Expand Up @@ -506,121 +499,6 @@
nshash_compare_by_id_p, 0);
}

// NSDictionary + NSMutableDictionary primitives. These are added automatically
// on singleton classes of pure NSDictionaries. Our implementation just calls
// the original methods, by tricking the receiver's class.

#define PREPARE_RCV(x) \
Class __old = *(Class *)x; \
*(Class *)x = (Class)rb_cCFHash;

#define RESTORE_RCV(x) \
*(Class *)x = __old;

static unsigned
nshash_count(id rcv, SEL sel)
{
PREPARE_RCV(rcv);
const unsigned count = [rcv count];
RESTORE_RCV(rcv);
return count;
}

static id
nshash_keyEnumerator(id rcv, SEL sel)
{
PREPARE_RCV(rcv);
id keys = [rcv allKeys];
RESTORE_RCV(rcv);
return [keys objectEnumerator];
}

static id
nshash_objectForKey(id rcv, SEL sel, id key)
{
PREPARE_RCV(rcv);
id value = [rcv objectForKey:key];
RESTORE_RCV(rcv);
return value;
}

static void
nshash_setObjectForKey(id rcv, SEL sel, id value, id key)
{
PREPARE_RCV(rcv);
[rcv setObject:value forKey:key];
RESTORE_RCV(rcv);
}

static void
nshash_getObjectsAndKeys(id rcv, SEL sel, id *objs, id *keys)
{
PREPARE_RCV(rcv);
[rcv getObjects:objs andKeys:keys];
RESTORE_RCV(rcv);
}

static void
nshash_removeObjectForKey(id rcv, SEL sel, id key)
{
PREPARE_RCV(rcv);
[rcv removeObjectForKey:key];
RESTORE_RCV(rcv);
}

static void
nshash_removeAllObjects(id rcv, SEL sel)
{
PREPARE_RCV(rcv);
[rcv removeAllObjects];
RESTORE_RCV(rcv);
}

static bool
nshash_isEqual(id rcv, SEL sel, id other)
{
PREPARE_RCV(rcv);
const bool res = [rcv isEqualToDictionary:other];
RESTORE_RCV(rcv);
return res;
}

static bool
nshash_containsObject(id rcv, SEL sel, id value)
{
PREPARE_RCV(rcv);
const bool res = [[rcv allKeysForObject:value] count] > 0;
RESTORE_RCV(rcv);
return res;
}

void
rb_objc_install_hash_primitives(Class klass)
{
rb_objc_install_method2(klass, "count", (IMP)nshash_count);
rb_objc_install_method2(klass, "keyEnumerator", (IMP)nshash_keyEnumerator);
rb_objc_install_method2(klass, "objectForKey:", (IMP)nshash_objectForKey);
rb_objc_install_method2(klass, "getObjects:andKeys:",
(IMP)nshash_getObjectsAndKeys);
rb_objc_install_method2(klass, "isEqual:", (IMP)nshash_isEqual);
rb_objc_install_method2(klass, "containsObject:",
(IMP)nshash_containsObject);

const bool mutable =
class_getSuperclass(klass) == (Class)rb_cNSMutableHash;

if (mutable) {
rb_objc_install_method2(klass, "setObject:forKey:",
(IMP)nshash_setObjectForKey);
rb_objc_install_method2(klass, "removeObjectForKey:",
(IMP)nshash_removeObjectForKey);
rb_objc_install_method2(klass, "removeAllObjects",
(IMP)nshash_removeAllObjects);
}

//rb_objc_define_method(*(VALUE *)klass, "alloc", hash_alloc, 0);
}

// MRI compatibility API.

VALUE
Expand Down
2 changes: 2 additions & 0 deletions array.c
Expand Up @@ -3484,6 +3484,8 @@ Init_Array(void)
Init_NSArray();

rb_cRubyArray = rb_define_class("Array", rb_cNSMutableArray);
RCLASS_SET_VERSION_FLAG(rb_cRubyArray, RCLASS_IS_ARRAY_SUBCLASS);

rb_objc_define_method(*(VALUE *)rb_cRubyArray, "new",
rb_class_new_instance_imp, -1);
rb_objc_define_method(*(VALUE *)rb_cRubyArray, "alloc", rary_alloc, 0);
Expand Down
79 changes: 30 additions & 49 deletions class.c
Expand Up @@ -20,44 +20,35 @@

extern st_table *rb_class_tbl;

void rb_objc_install_array_primitives(Class);
void rb_objc_install_hash_primitives(Class);
void rb_objc_install_string_primitives(Class);
void rb_objc_install_set_primitives(Class);

bool
rb_objc_install_primitives(Class ocklass, Class ocsuper)
{
if (rb_cRubyArray != 0 && rb_cRubyHash != 0 && rb_cString != 0) {
do {
if (ocsuper == (Class)rb_cRubyArray) {
RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_ARRAY_SUBCLASS);
return false;
}
if (ocsuper == (Class)rb_cArray) {
rb_objc_install_array_primitives(ocklass);
RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_ARRAY_SUBCLASS);
return true;
}
if (ocsuper == (Class)rb_cRubyHash) {
RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_HASH_SUBCLASS);
return false;
}
if (ocsuper == (Class)rb_cHash) {
rb_objc_install_hash_primitives(ocklass);
RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_HASH_SUBCLASS);
return true;
}
if (ocsuper == (Class)rb_cString) {
rb_objc_install_string_primitives(ocklass);
RCLASS_SET_VERSION_FLAG(ocklass, RCLASS_IS_STRING_SUBCLASS);
return true;
}
ocsuper = class_getSuperclass(ocsuper);
}
while (ocsuper != NULL);
void
rb_objc_class_sync_version(Class ocklass, Class ocsuper)
{
const long super_version = RCLASS_VERSION(ocsuper);
long klass_version = RCLASS_VERSION(ocklass);

if ((super_version & RCLASS_NO_IV_SLOTS) == RCLASS_NO_IV_SLOTS) {
klass_version |= RCLASS_NO_IV_SLOTS;
}

if (ocsuper == (Class)rb_cObject
|| (super_version & RCLASS_IS_OBJECT_SUBCLASS)
== RCLASS_IS_OBJECT_SUBCLASS) {
klass_version |= RCLASS_IS_OBJECT_SUBCLASS;
}
if ((super_version & RCLASS_IS_ARRAY_SUBCLASS)
== RCLASS_IS_ARRAY_SUBCLASS) {
klass_version |= RCLASS_IS_ARRAY_SUBCLASS;
}
return false;
if ((super_version & RCLASS_IS_HASH_SUBCLASS)
== RCLASS_IS_HASH_SUBCLASS) {
klass_version |= RCLASS_IS_HASH_SUBCLASS;
}
if ((super_version & RCLASS_IS_STRING_SUBCLASS)
== RCLASS_IS_STRING_SUBCLASS) {
klass_version |= RCLASS_IS_STRING_SUBCLASS;
}

RCLASS_SET_VERSION(ocklass, klass_version);
}

static void *
Expand Down Expand Up @@ -193,22 +184,12 @@ rb_objc_alloc_class(const char *name, VALUE super, VALUE flags, VALUE klass)
if (flags == T_MODULE) {
version_flag |= RCLASS_IS_MODULE;
}
const long super_version = RCLASS_VERSION(super);
if (super == rb_cObject
|| (super_version & RCLASS_IS_OBJECT_SUBCLASS)
== RCLASS_IS_OBJECT_SUBCLASS) {
version_flag |= RCLASS_IS_OBJECT_SUBCLASS;
}
if ((super_version & RCLASS_NO_IV_SLOTS) == RCLASS_NO_IV_SLOTS) {
version_flag |= RCLASS_NO_IV_SLOTS;
}

RCLASS_SET_VERSION(ocklass, version_flag);

objc_registerClassPair(ocklass);

if (klass != 0) {
rb_objc_install_primitives(ocklass, (Class)super);
rb_objc_class_sync_version(ocklass, (Class)super);
}

return (VALUE)ocklass;
Expand Down Expand Up @@ -348,7 +329,7 @@ rb_class_init_copy(VALUE clone, SEL sel, VALUE orig)
rb_raise(rb_eTypeError, "can't copy singleton class");
}
clone = rb_mod_init_copy(clone, 0, orig);
rb_objc_install_primitives((Class)clone, (Class)orig);
rb_objc_class_sync_version((Class)clone, (Class)orig);
return clone;
}

Expand Down

0 comments on commit 2aae14f

Please sign in to comment.