Permalink
Browse files

fix Module objects to not inherit from Object, to behave like CRuby

  • Loading branch information...
1 parent 1465dde commit bfcea02f4036e5fb7c7f674564c9f8cf6e68beb3 Laurent Sansonetti committed Apr 29, 2011
Showing with 66 additions and 55 deletions.
  1. +3 −1 class.c
  2. +29 −26 gc.c
  3. +8 −0 object.c
  4. +8 −0 vm.cpp
  5. +18 −28 vm_method.c
View
4 class.c
@@ -22,6 +22,7 @@
extern st_table *rb_class_tbl;
extern VALUE rb_cRubyObject;
+extern VALUE rb_cModuleObject;
VALUE
rb_class_super(VALUE klass)
@@ -522,7 +523,8 @@ VALUE
rb_define_module_id(ID id)
{
const char *name = id == 0 ? NULL : rb_id2name(id);
- VALUE mdl = rb_objc_alloc_class(name, rb_cObject, T_MODULE, rb_cModule);
+ VALUE mdl = rb_objc_alloc_class(name, rb_cModuleObject, T_MODULE,
+ rb_cModule);
if (rb_mKernel != 0 && id == 0) {
// Because Module#initialize can accept a block.
rb_objc_define_method(*(VALUE *)mdl, "initialize",
View
55 gc.c
@@ -516,41 +516,44 @@ struct rb_objc_recorder_context {
static int
rb_objc_yield_classes(VALUE of)
{
- int i, count, rcount;
- Class *buf;
-
- count = objc_getClassList(NULL, 0);
+ const int count = objc_getClassList(NULL, 0);
assert(count > 0);
- buf = (Class *)alloca(sizeof(Class) * count);
+ Class *buf = (Class *)alloca(sizeof(Class) * count);
objc_getClassList(buf, count);
+ const bool only_modules = of == rb_cModule;
- for (i = rcount = 0; i < count; i++) {
- Class sk, k = buf[i];
- bool nsobject_based;
-
- if (class_getName(k)[0] == '_')
- continue;
-
- if (of == rb_cModule && !RCLASS_MODULE(k))
+ int rcount = 0;
+ for (int i = 0; i < count; i++) {
+ Class k = buf[i];
+ if (class_getName(k)[0] == '_') {
continue;
+ }
- nsobject_based = false;
- sk = k;
- do {
- sk = (Class)RCLASS_SUPER(sk);
- if (sk == (Class)rb_cNSObject) {
- nsobject_based = true;
- break;
+ if (only_modules) {
+ if (!RCLASS_MODULE(k)) {
+ continue;
}
}
- while (sk != NULL);
-
- if (nsobject_based) {
- rb_yield((VALUE)k);
- RETURN_IF_BROKEN();
- rcount++;
+ else {
+ bool nsobject_based = false;
+ Class sk = k;
+ do {
+ sk = (Class)RCLASS_SUPER(sk);
+ if (sk == (Class)rb_cNSObject) {
+ nsobject_based = true;
+ break;
+ }
+ }
+ while (sk != NULL);
+ if (!nsobject_based) {
+ continue;
+ }
}
+
+ rb_yield((VALUE)k);
+ RETURN_IF_BROKEN();
+ rcount++;
}
return rcount;
View
8 object.c
@@ -32,6 +32,7 @@ VALUE rb_cNSObject;
VALUE rb_cObject;
VALUE rb_cRubyObject;
VALUE rb_cModule;
+VALUE rb_cModuleObject;
VALUE rb_cClass;
VALUE rb_cData;
@@ -3058,6 +3059,13 @@ Init_Object(void)
rb_define_object_special_methods(rb_cRubyObject);
rb_objc_install_NSObject_special_methods((Class)rb_cRubyObject);
+ // Every instance of the Module class inherits from this class, which is
+ // a duplicate of NSObject. This is because the CRuby standard does not
+ // make Module instances inherit from Object (and Kernel).
+ rb_cModuleObject = (VALUE)objc_duplicateClass((Class)rb_cObject,
+ "__ModuleObject", 0);
+ assert(rb_cModuleObject != 0);
+
eqlSel = sel_registerName("eql?:");
rb_objc_define_method(*(VALUE *)rb_cModule, "alloc", rb_module_s_alloc, 0);
View
8 vm.cpp
@@ -1603,16 +1603,24 @@ vm_alias(VALUE outer, ID name, ID def)
VALUE dest = outer;
Class klass = (Class)outer;
Class dest_klass = (Class)dest;
+ const bool klass_is_mod = TYPE(klass) == T_MODULE;
const char *def_str = rb_id2name(def);
SEL sel = sel_registerName(def_str);
Method def_method1 = class_getInstanceMethod(klass, sel);
+ if (def_method1 == NULL && klass_is_mod) {
+ def_method1 = class_getInstanceMethod((Class)rb_cObject, sel);
+ }
+
Method def_method2 = NULL;
if (def_str[strlen(def_str) - 1] != ':') {
char tmp[100];
snprintf(tmp, sizeof tmp, "%s:", def_str);
sel = sel_registerName(tmp);
def_method2 = class_getInstanceMethod(klass, sel);
+ if (def_method2 == NULL && klass_is_mod) {
+ def_method2 = class_getInstanceMethod((Class)rb_cObject, sel);
+ }
}
if (def_method1 == NULL && def_method2 == NULL) {
View
46 vm_method.c
@@ -87,7 +87,8 @@ rb_export_method(VALUE klass, ID name, ID noex)
if (!rb_vm_lookup_method2((Class)klass, name, &sel, NULL, &node)) {
if (TYPE(klass) != T_MODULE
- || !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL, &node)) {
+ || !rb_vm_lookup_method2((Class)rb_cObject, name, &sel, NULL,
+ &node)) {
rb_print_undef(klass, name, 0);
}
}
@@ -112,28 +113,14 @@ rb_export_method(VALUE klass, ID name, ID noex)
break;
}
- VALUE sklass = RCLASS_SUPER(klass);
- if (sklass != 0) {
- IMP imp;
- rb_vm_method_node_t *snode;
- if (rb_vm_lookup_method((Class)sklass, sel, &imp, &snode)
- && imp == node->objc_imp) {
- // The method actually exists on a superclass, we need to duplicate
- // it to the current class, keeping the same flags.
- if (snode != NULL) {
- if (snode->flags & VM_METHOD_EMPTY) {
- flags |= VM_METHOD_EMPTY;
- }
- if (snode->flags & VM_METHOD_FBODY) {
- flags |= VM_METHOD_FBODY;
- }
- }
+ if (node->flags != flags) {
+ if (node->klass == (Class)klass) {
+ node->flags = flags;
+ }
+ else {
rb_vm_define_method2((Class)klass, sel, node, flags, false);
- return;
}
}
-
- node->flags = flags;
}
void
@@ -645,16 +632,19 @@ rb_mod_modfunc(VALUE module, SEL sel, int argc, VALUE *argv)
for (int i = 0; i < argc; i++) {
ID id = rb_to_id(argv[i]);
- IMP imp;
- rb_vm_method_node_t *node;
- SEL sel;
-
- if (!rb_vm_lookup_method2((Class)module, id, &sel, &imp, &node)) {
- // Methods are checked in set_method_visibility().
+ IMP imp = NULL;
+ rb_vm_method_node_t *node = NULL;
+ SEL sel = 0;
+
+ if (rb_vm_lookup_method2((Class)module, id, &sel, &imp, &node)
+ || (TYPE(module) == T_MODULE
+ && rb_vm_lookup_method2((Class)rb_cObject, id, &sel,
+ &imp, &node))) {
+ rb_vm_define_method2(*(Class *)module, sel, node, -1, false);
+ }
+ else {
rb_bug("undefined method `%s'; can't happen", rb_id2name(id));
}
-
- rb_vm_define_method2(*(Class *)module, sel, node, -1, false);
}
return module;

0 comments on commit bfcea02

Please sign in to comment.