Skip to content
Browse files

when registering a new method, if the given class also responds to th…

…e arity-1+1 selector let's make it unavailable, to fully conform to the way Ruby behaves

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@2941 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 2c14d71 commit 277a9ee609226dd42191e4b7fe9eed6b947b7656 Laurent Sansonetti committed Nov 3, 2009
Showing with 58 additions and 31 deletions.
  1. +23 −14 dispatcher.cpp
  2. +32 −15 vm.cpp
  3. +3 −2 vm.h
View
37 dispatcher.cpp
@@ -221,9 +221,20 @@ static Method
rb_vm_super_lookup(VALUE klass, SEL sel)
{
// Locate the current method implementation.
- Method m = class_getInstanceMethod((Class)klass, sel);
- assert(m != NULL);
- IMP self = objc_imp(method_getImplementation(m));
+ Class k = (Class)klass;
+ IMP self;
+ while (true) {
+ Method m = class_getInstanceMethod(k, sel);
+ assert(m != NULL);
+ self = method_getImplementation(m);
+ if (UNAVAILABLE_IMP(self)) {
+ k = class_getSuperclass(k);
+ assert(k != NULL);
+ }
+ else {
+ break;
+ }
+ }
// Compute the stack call implementations right after our current method.
void *callstack[128];
@@ -248,7 +259,6 @@ rb_vm_super_lookup(VALUE klass, SEL sel)
// the stack.
VALUE ary = rb_mod_ancestors_nocopy(klass);
const int count = RARRAY_LEN(ary);
- VALUE k = klass;
bool klass_located = false;
#if ROXOR_VM_DEBUG
@@ -272,18 +282,21 @@ rb_vm_super_lookup(VALUE klass, SEL sel)
}
if (klass_located) {
if (i < count - 1) {
- k = RARRAY_AT(ary, i + 1);
+ VALUE k = RARRAY_AT(ary, i + 1);
Method method = class_getInstanceMethod((Class)k, sel);
VALUE super = RCLASS_SUPER(k);
- if (method == NULL || REMOVED_IMP(method_getImplementation(method))
- || (super != 0
- && class_getInstanceMethod((Class)super, sel) == method)) {
+ if (method == NULL) {
continue;
}
IMP imp = method_getImplementation(method);
+ if (UNAVAILABLE_IMP(imp)
+ || (super != 0 && class_getInstanceMethod((Class)super,
+ sel) == method)) {
+ continue;
+ }
if (std::find(callstack_funcs.begin(), callstack_funcs.end(),
(void *)imp) == callstack_funcs.end()) {
@@ -556,9 +569,7 @@ __rb_vm_dispatch(RoxorVM *vm, struct mcache *cache, VALUE top, VALUE self,
recache2:
IMP imp = method_getImplementation(method);
- if (UNDEFINED_IMP(imp)
- || (REMOVED_IMP(imp)
- && rb_vm_super_lookup((VALUE)klass, sel) == NULL)) {
+ if (UNAVAILABLE_IMP(imp)) {
// Method was undefined.
goto call_method_missing;
}
@@ -1769,9 +1780,7 @@ rb_vm_respond_to(VALUE obj, SEL sel, bool priv)
}
IMP imp = method_getImplementation(m);
- if (UNDEFINED_IMP(imp)
- || (REMOVED_IMP(imp)
- && rb_vm_super_lookup((VALUE)klass, sel) == NULL)) {
+ if (UNAVAILABLE_IMP(imp)) {
return false;
}
View
47 vm.cpp
@@ -1379,6 +1379,9 @@ static void
rb_vm_alias_method(Class klass, Method method, ID name, bool noargs)
{
IMP imp = method_getImplementation(method);
+ if (UNAVAILABLE_IMP(imp)) {
+ return;
+ }
const char *types = method_getTypeEncoding(method);
rb_vm_method_node_t *node = GET_CORE()->method_node_get(method);
@@ -1806,7 +1809,9 @@ prepare_method(Class klass, bool dynamic_class, SEL sel, void *data,
m = class_getInstanceMethod(klass, sel);
if (precompiled) {
- imp = (IMP)data;
+ if (imp == NULL) {
+ imp = (IMP)data;
+ }
GET_CORE()->resolve_method(klass, sel, NULL, arity, flags, imp, m);
}
else {
@@ -1825,22 +1830,33 @@ prepare_method(Class klass, bool dynamic_class, SEL sel, void *data,
}
if (!redefined) {
- if (!genuine_selector && arity.max != arity.min) {
- char buf[100];
+ char buf[100];
+ SEL new_sel = 0;
+ if (!genuine_selector) {
snprintf(buf, sizeof buf, "%s:", sel_name);
- sel = sel_registerName(buf);
- redefined = true;
-
- goto prepare_method;
+ new_sel = sel_registerName(buf);
+ if (arity.max != arity.min) {
+ sel = new_sel;
+ redefined = true;
+ goto prepare_method;
+ }
}
- else if (genuine_selector && arity.min == 0) {
- char buf[100];
+ else {
strlcpy(buf, sel_name, sizeof buf);
buf[strlen(buf) - 1] = 0; // remove the ending ':'
- sel = sel_registerName(buf);
- redefined = true;
-
- goto prepare_method;
+ new_sel = sel_registerName(buf);
+ if (arity.min == 0) {
+ sel = new_sel;
+ redefined = true;
+ goto prepare_method;
+ }
+ }
+ Method tmp_m = class_getInstanceMethod(klass, new_sel);
+ if (tmp_m != NULL) {
+ // If we add -[foo:] and the class responds to -[foo], we need
+ // to disable it (and vice-versa).
+ class_replaceMethod(klass, new_sel,
+ (IMP)rb_vm_undefined_imp, method_getTypeEncoding(tmp_m));
}
}
@@ -2131,6 +2147,9 @@ rb_vm_lookup_method(Class klass, SEL sel, IMP *pimp,
return false;
}
IMP imp = method_getImplementation(m);
+ if (UNAVAILABLE_IMP(imp)) {
+ return false;
+ }
if (pimp != NULL) {
*pimp = imp;
}
@@ -2259,8 +2278,6 @@ rb_vm_define_method3(Class klass, SEL sel, rb_vm_block_t *block)
rb_vm_define_method(klass, sel, imp, body, false);
}
-#define UNDEFINED_IMP(imp) (imp == NULL || imp == (IMP)rb_vm_undefined_imp)
-
void
RoxorCore::undef_method(Class klass, SEL sel)
{
View
5 vm.h
@@ -283,9 +283,10 @@ rb_vm_method_node_t *rb_vm_define_method2(Class klass, SEL sel,
void rb_vm_define_method3(Class klass, SEL sel, rb_vm_block_t *node);
bool rb_vm_resolve_method(Class klass, SEL sel);
void *rb_vm_undefined_imp(void *rcv, SEL sel);
-#define UNDEFINED_IMP(imp) (imp == NULL || imp == (IMP)rb_vm_undefined_imp)
void *rb_vm_removed_imp(void *rcv, SEL sel);
-#define REMOVED_IMP(imp) (imp == (IMP)rb_vm_removed_imp)
+#define UNAVAILABLE_IMP(imp) \
+ (imp == NULL || imp == (IMP)rb_vm_undefined_imp \
+ || imp == (IMP)rb_vm_removed_imp)
void rb_vm_define_attr(Class klass, const char *name, bool read, bool write);
void rb_vm_undef_method(Class klass, ID name, bool must_exist);
void rb_vm_alias(VALUE klass, ID name, ID def);

0 comments on commit 277a9ee

Please sign in to comment.
Something went wrong with that request. Please try again.