Permalink
Browse files

work in progress on the new c/objc dispatcher

  • Loading branch information...
1 parent ad6ef44 commit 928f4e8bd200738c84bb59e74a9e3e9e169920a3 @lrz lrz committed Apr 17, 2009
Showing with 130 additions and 22 deletions.
  1. +17 −10 class.c
  2. +90 −6 roxor.cpp
  3. +1 −0 roxor.h
  4. +21 −5 spec/frozen/macruby/method_spec.rb
  5. +1 −1 vm_method.c
View
27 class.c
@@ -746,7 +746,8 @@ ins_methods_pub_i(VALUE name, ID type, VALUE ary)
}
static void
-rb_objc_push_methods(VALUE ary, VALUE mod, VALUE objc_methods, int (*func) (VALUE, ID, VALUE))
+rb_objc_push_methods(VALUE ary, VALUE mod, VALUE objc_methods,
+ int (*func) (VALUE, ID, VALUE))
{
Method *methods;
unsigned int i, count;
@@ -770,17 +771,20 @@ rb_objc_push_methods(VALUE ary, VALUE mod, VALUE objc_methods, int (*func) (VALU
method = methods[i];
sel = method_getName(method);
- if (sel == sel_ignored)
+ if (sel == sel_ignored) {
continue;
+ }
imp = method_getImplementation(method);
- if (imp == NULL)
+ if (imp == NULL) {
continue;
+ }
- mn = rb_objc_method_node3(imp);
+ mn = rb_vm_get_method_node(imp);
is_ruby_method = mn != NULL;
- if (!is_ruby_method && objc_methods == Qfalse)
+ if (!is_ruby_method && objc_methods == Qfalse) {
continue;
+ }
sel_name = (char *)sel;
len = strlen(sel_name);
@@ -803,7 +807,7 @@ rb_objc_push_methods(VALUE ary, VALUE mod, VALUE objc_methods, int (*func) (VALU
buf[len + 2] = '\0';
method = class_getInstanceMethod((Class)mod, sel_registerName(buf));
- if (method != NULL && rb_objc_method_node3(method_getImplementation(method)) == NULL)
+ if (method != NULL && rb_vm_get_method_node(method_getImplementation(method)) == NULL)
continue;
}
else if (sel_name[len - 2] == '?') {
@@ -814,7 +818,7 @@ rb_objc_push_methods(VALUE ary, VALUE mod, VALUE objc_methods, int (*func) (VALU
buf[len + 1] = '\0';
method = class_getInstanceMethod((Class)mod, sel_registerName(buf));
- if (method != NULL && rb_objc_method_node3(method_getImplementation(method)) == NULL)
+ if (method != NULL && rb_vm_get_method_node(method_getImplementation(method)) == NULL)
continue;
}
}
@@ -860,16 +864,19 @@ class_instance_method_list(int argc, VALUE *argv, VALUE mod, int (*func) (VALUE,
}
else {
rb_scan_args(argc, argv, "02", &recur, &objc_methods);
- if (NIL_P(recur))
+ if (NIL_P(recur)) {
recur = Qtrue;
- if (NIL_P(objc_methods))
+ }
+ if (NIL_P(objc_methods)) {
objc_methods = Qfalse;
+ }
}
while (mod != 0) {
rb_objc_push_methods(ary, mod, objc_methods, func);
- if (recur == Qfalse)
+ if (recur == Qfalse) {
break;
+ }
mod = (VALUE)class_getSuperclass((Class)mod);
}
View
@@ -2440,6 +2440,13 @@ RoxorVM::method_node_get(IMP imp)
return iter->second->node;
}
+extern "C"
+NODE *
+rb_vm_get_method_node(IMP imp)
+{
+ return GET_VM()->method_node_get(imp);
+}
+
inline GlobalVariable *
RoxorVM::redefined_op_gvar(SEL sel, bool create)
{
@@ -4789,11 +4796,36 @@ RoxorCompiler::compile_conversion_to_c(const char *type, Value *val, Value *slot
return new LoadInst(slot, "", bb);
}
+extern "C"
+VALUE
+rb_vm_ocval_to_rval(void *ocval)
+{
+ return SPECIAL_CONST_P(ocval) ? (VALUE)ocval : OC2RB(ocval);
+}
+
Value *
RoxorCompiler::compile_conversion_to_ruby(const char *type, Value *val)
{
- // TODO
- return val;
+ const char *func_name = NULL;
+
+ switch (*type) {
+ case _C_ID:
+ case _C_CLASS:
+ func_name = "rb_vm_ocval_to_rval";
+ break;
+
+ default:
+ printf("unrecognized compile type `%s' to Ruby - aborting\n", type);
+ abort();
+ }
+
+ std::vector<Value *> params;
+ params.push_back(val);
+
+ Function *func = cast<Function>(module->getOrInsertFunction(
+ func_name, RubyObjTy, convert_type(type), NULL));
+
+ return CallInst::Create(func, params.begin(), params.end(), "", bb);
}
inline const Type *
@@ -4872,6 +4904,7 @@ RoxorCompiler::compile_stub(const char *types, int argc, bool is_objc)
p = SkipFirstType(p);
f_types.push_back(RubyObjTy);
params.push_back(self_arg);
+
// sel
p = SkipFirstType(p);
f_types.push_back(PtrTy);
@@ -6121,6 +6154,33 @@ vm_gen_stub(const char *types, int argc, bool is_objc)
return stub;
}
+static inline SEL
+helper_sel(SEL sel)
+{
+ const char *p = sel_getName(sel);
+ long len = strlen(p);
+ SEL new_sel = 0;
+ char buf[100];
+
+ if (len >= 3 && isalpha(p[len - 3]) && p[len - 2] == '=' && p[len - 1] == ':') {
+ /* foo=: -> setFoo: shortcut */
+ snprintf(buf, sizeof buf, "set%s", p);
+ buf[3] = toupper(buf[3]);
+ buf[len + 1] = ':';
+ buf[len + 2] = '\0';
+ new_sel = sel_registerName(buf);
+ }
+ else if (isalpha(p[len - 2]) && p[len - 1] == '?') {
+ /* foo?: -> isFoo: shortcut */
+ snprintf(buf, sizeof buf, "is%s", p);
+ buf[2] = toupper(buf[2]);
+ buf[len + 1] = '\0';
+ new_sel = sel_registerName(buf);
+ }
+
+ return new_sel;
+}
+
__attribute__((always_inline))
static VALUE
__rb_vm_dispatch(struct mcache *cache, VALUE self, Class klass, SEL sel,
@@ -6182,6 +6242,19 @@ __rb_vm_dispatch(struct mcache *cache, VALUE self, Class klass, SEL sel,
}
}
else {
+ SEL new_sel = helper_sel(sel);
+ if (new_sel != NULL) {
+ Method m = class_getInstanceMethod(klass, new_sel);
+ if (m != NULL) {
+ IMP imp = method_getImplementation(m);
+ if (GET_VM()->method_node_get(imp) == NULL) {
+ sel = new_sel;
+ method = m;
+ goto recache;
+ }
+ }
+ }
+
// TODO bridgesupport C call?
return method_missing((VALUE)self, sel, argc, argv, opt);
}
@@ -6909,12 +6982,23 @@ rb_vm_respond_to(VALUE obj, SEL sel, bool priv)
selRespondTo);
if (respond_to_imp == basic_respond_to_imp) {
- IMP obj_imp = class_getMethodImplementation((Class)klass, sel);
- if (obj_imp == NULL) {
- return false;
+ Method m = class_getInstanceMethod((Class)klass, sel);
+ if (m == NULL) {
+ sel = helper_sel(sel);
+ if (sel != NULL) {
+ m = class_getInstanceMethod((Class)klass, sel);
+ }
+ if (m == NULL) {
+ return false;
+ }
}
+ IMP obj_imp = method_getImplementation(m);
NODE *node = GET_VM()->method_node_get(obj_imp);
- return node != NULL && (!priv || !(node->nd_noex & NOEX_PRIVATE));
+
+ if (node != NULL && priv == 0 && (node->nd_noex & NOEX_PRIVATE)) {
+ return false;
+ }
+ return obj_imp != NULL;
}
else {
VALUE args[2];
View
@@ -65,6 +65,7 @@ VALUE rb_vm_top_self(void);
void rb_vm_const_is_defined(ID path);
bool rb_vm_lookup_method(Class klass, SEL sel, IMP *pimp, NODE **pnode);
bool rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp, NODE **pnode);
+NODE *rb_vm_get_method_node(IMP imp);
void rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node, bool direct);
void rb_vm_define_attr(Class klass, const char *name, bool read, bool write, int noex);
void rb_vm_alias(VALUE klass, ID name, ID def);
@@ -19,8 +19,10 @@ def o.doSomething(x, withObject:y, withObject:z); x + y + z; end
o = Object.new
def o.foo(x); x; end
def o.foo(x, withObject:y); x + y; end
+ def o.foo(x, withObject:y, andObject:z); x + y + z; end
o.respond_to?(:'foo').should == true
o.respond_to?(:'foo:withObject:').should == true
+ o.respond_to?(:'foo:withObject:andObject:').should == true
end
it "must start by a regular argument variable then followed by argument-names" do
@@ -71,6 +73,20 @@ def o.doSomething(x, withObject:y); x + y; end
o.performSelector(:'doSomething:withObject:',
withObject:40, withObject:2).should == 42
end
+
+ it "named using the setFoo pattern cannot be called using #foo=" do
+ o = Object.new
+ def o.setFoo(x); end
+ o.respond_to?(:'foo=').should == false
+ lambda { o.foo = 42 }.should raise_error(NoMethodError)
+ end
+
+ it "named using the isFoo pattern cannot be called using #foo?" do
+ o = Object.new
+ def o.isFoo; end
+ o.respond_to?(:'foo?').should == false
+ lambda { o.foo? }.should raise_error(NoMethodError)
+ end
end
describe "An Objective-C method" do
@@ -91,10 +107,10 @@ def o.doSomething(x, withObject:y); x + y; end
it "is only exposed in #methods if the second argument is true" do
o = Object.new
- o.methods.include?(:'performSelector:').should == false
- o.methods(true).include?(:'performSelector:').should == false
- o.methods(false).include?(:'performSelector:').should == false
- o.methods(true, true).include?(:'performSelector:').should == true
- o.methods(false, true).include?(:'performSelector:').should == true
+ o.methods.include?(:'performSelector').should == false
+ o.methods(true).include?(:'performSelector').should == false
+ o.methods(false).include?(:'performSelector').should == false
+ o.methods(true, true).include?(:'performSelector').should == true
+ o.methods(false, true).include?(:'performSelector').should == true
end
end
View
@@ -815,7 +815,7 @@ rb_obj_respond_to(VALUE obj, ID id, int priv)
char buf[100];
snprintf(buf, sizeof buf, "%s:", id_name);
sel = sel_registerName(buf);
- return rb_vm_respond_to(obj, sel, priv) == true;
+ return rb_vm_respond_to(obj, sel, priv) == true ? 1 : 0;
}
return 1;
}

0 comments on commit 928f4e8

Please sign in to comment.