[macruby-changes] [291] MacRuby/trunk/objc.m
source_changes at macosforge.org
source_changes at macosforge.org
Sun Jun 15 19:21:00 PDT 2008
Revision: 291
http://trac.macosforge.org/projects/ruby/changeset/291
Author: lsansonetti at apple.com
Date: 2008-06-15 19:21:00 -0700 (Sun, 15 Jun 2008)
Log Message:
-----------
more performance work on the objc dispatcher
Modified Paths:
--------------
MacRuby/trunk/objc.m
Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m 2008-06-15 08:42:22 UTC (rev 290)
+++ MacRuby/trunk/objc.m 2008-06-16 02:21:00 UTC (rev 291)
@@ -1057,53 +1057,58 @@
extern NODE *rb_current_cfunc_node;
+struct objc_ruby_closure_context {
+ SEL selector;
+ bs_element_method_t *bs_method;
+ Method method;
+ ffi_cif *cif;
+ IMP imp;
+};
+
static VALUE
rb_objc_to_ruby_closure(int argc, VALUE *argv, VALUE rcv)
{
- Method method;
unsigned i, real_count, count;
ffi_type *ffi_rettype, **ffi_argtypes;
void *ffi_ret, **ffi_args;
ffi_cif *cif;
Class klass;
- SEL selector;
const char *type;
char buf[128];
id ocrcv;
void *imp;
- bs_element_method_t *bs_method;
+ struct objc_ruby_closure_context *ctx;
+ bool super_call;
+ super_call = (ruby_current_thread->cfp->flag >> FRAME_MAGIC_MASK_BITS)
+ & VM_CALL_SUPER_BIT;
+
rb_objc_rval_to_ocid(rcv, (void **)&ocrcv);
klass = *(Class *)ocrcv;
assert(rb_current_cfunc_node != NULL);
if (rb_current_cfunc_node->u3.value == 0) {
- selector = sel_registerName(rb_id2name(rb_frame_this_func()));
- bs_method = rb_bs_find_method(klass, selector);
- if (bs_method != NULL)
- rb_current_cfunc_node->u3.value = (VALUE)bs_method;
- else
- rb_current_cfunc_node->u3.value = Qnil;
+ ctx = (struct objc_ruby_closure_context *)xmalloc(sizeof(
+ struct objc_ruby_closure_context));
+ ctx->selector = sel_registerName(rb_id2name(rb_frame_this_func()));
+ ctx->bs_method = rb_bs_find_method(klass, ctx->selector);
+ ctx->method = class_getInstanceMethod(klass, ctx->selector);
+ ctx->cif = NULL;
+ ctx->imp = NULL;
+ assert(ctx->method != NULL);
+ GC_WB(&rb_current_cfunc_node->u3.value, ctx);
}
else {
- if (rb_current_cfunc_node->u3.value == Qnil) {
- bs_method = NULL;
- selector = sel_registerName(rb_id2name(rb_frame_this_func()));
- }
- else {
- bs_method = (bs_element_method_t *)rb_current_cfunc_node->u3.value;
- selector = bs_method->name;
- }
+ ctx = (struct objc_ruby_closure_context *)
+ rb_current_cfunc_node->u3.value;
}
- method = class_getInstanceMethod(klass, selector);
- assert(method != NULL);
- count = method_getNumberOfArguments(method);
+ count = method_getNumberOfArguments(ctx->method);
assert(count >= 2);
real_count = count;
- if (bs_method != NULL && bs_method->variadic) {
+ if (ctx->bs_method != NULL && ctx->bs_method->variadic) {
if (argc < count - 2)
rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
argc, count - 2);
@@ -1115,11 +1120,19 @@
}
if (count == 2) {
- method_getReturnType(method, buf, sizeof buf);
+ method_getReturnType(ctx->method, buf, sizeof buf);
if (buf[0] == '@' || buf[0] == 'v') {
/* Easy case! */
@try {
- ffi_ret = objc_msgSend(ocrcv, selector);
+ if (super_call) {
+ struct objc_super s;
+ s.receiver = ocrcv;
+ s.class = class_getSuperclass(*(Class *)ocrcv);
+ ffi_ret = objc_msgSendSuper(&s, ctx->selector);
+ }
+ else {
+ ffi_ret = objc_msgSend(ocrcv, ctx->selector);
+ }
}
@catch (id e) {
rb_objc_exc_raise(e);
@@ -1128,53 +1141,79 @@
}
}
- ffi_argtypes = (ffi_type **)alloca(sizeof(ffi_type *) * (count + 1));
- ffi_argtypes[0] = &ffi_type_pointer;
- ffi_argtypes[1] = &ffi_type_pointer;
+ if (ctx->cif == NULL) {
+ const size_t s = sizeof(ffi_type *) * (count + 1);
+ ffi_argtypes = ctx->bs_method != NULL && ctx->bs_method->variadic
+ ? (ffi_type **)alloca(s) : (ffi_type **)malloc(s);
+ ffi_argtypes[0] = &ffi_type_pointer;
+ ffi_argtypes[1] = &ffi_type_pointer;
+ }
ffi_args = (void **)alloca(sizeof(void *) * (count + 1));
ffi_args[0] = &ocrcv;
- ffi_args[1] = &selector;
+ ffi_args[1] = &ctx->selector;
- if ((ruby_current_thread->cfp->flag >> FRAME_MAGIC_MASK_BITS)
- & VM_CALL_SUPER_BIT) {
+ if (super_call) {
Class sklass;
Method smethod;
sklass = class_getSuperclass(klass);
assert(sklass != NULL);
- smethod = class_getInstanceMethod(sklass, selector);
- assert(smethod != method);
+ smethod = class_getInstanceMethod(sklass, ctx->selector);
+ assert(smethod != ctx->method);
imp = method_getImplementation(smethod);
}
else {
- imp = method == class_getInstanceMethod(klass, selector)
- ? method_getImplementation(method)
- : objc_msgSend; /* alea jacta est */
+ if (ctx->imp != NULL) {
+ imp = ctx->imp;
+ }
+ else {
+ ctx->imp = imp = ctx->method ==
+ class_getInstanceMethod(klass, ctx->selector)
+ ? method_getImplementation(ctx->method)
+ : objc_msgSend; /* alea jacta est */
+ }
}
for (i = 0; i < argc; i++) {
- type = rb_objc_method_get_type(method, real_count, bs_method, i, buf,
- sizeof buf);
- ffi_argtypes[i + 2] = rb_objc_octype_to_ffitype(type);
- assert(ffi_argtypes[i + 2]->size > 0);
- ffi_args[i + 2] = (void *)alloca(ffi_argtypes[i + 2]->size);
+ ffi_type *ffi_argtype;
+
+ type = rb_objc_method_get_type(ctx->method, real_count, ctx->bs_method,
+ i, buf, sizeof buf);
+
+ if (ctx->cif == NULL) {
+ ffi_argtypes[i + 2] = rb_objc_octype_to_ffitype(type);
+ assert(ffi_argtypes[i + 2]->size > 0);
+ ffi_argtype = ffi_argtypes[i + 2];
+ }
+ else {
+ ffi_argtype = ctx->cif->arg_types[i + 2];
+ }
+
+ ffi_args[i + 2] = (void *)alloca(ffi_argtype->size);
rb_objc_rval_to_ocval(argv[i], type, ffi_args[i + 2]);
}
- ffi_argtypes[count] = NULL;
+ if (ctx->cif == NULL)
+ ffi_argtypes[count] = NULL;
ffi_args[count] = NULL;
- type = rb_objc_method_get_type(method, real_count, bs_method, -1, buf,
- sizeof buf);
- ffi_rettype = rb_objc_octype_to_ffitype(type);
+ type = rb_objc_method_get_type(ctx->method, real_count, ctx->bs_method,
+ -1, buf, sizeof buf);
+ ffi_rettype = ctx->cif == NULL
+ ? rb_objc_octype_to_ffitype(type) : ctx->cif->rtype;
- cif = (ffi_cif *)alloca(sizeof(ffi_cif));
- if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, count, ffi_rettype,
- ffi_argtypes)
- != FFI_OK)
- rb_fatal("can't prepare cif for objc method type `%s'",
- method_getTypeEncoding(method));
-
+ cif = ctx->cif;
+ if (cif == NULL) {
+ if (ctx->bs_method != NULL && ctx->bs_method->variadic)
+ cif = (ffi_cif *)alloca(sizeof(ffi_cif));
+ else
+ cif = ctx->cif = (ffi_cif *)malloc(sizeof(ffi_cif));
+ if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, count, ffi_rettype,
+ ffi_argtypes) != FFI_OK) {
+ rb_fatal("can't prepare cif for objc method type `%s'",
+ method_getTypeEncoding(ctx->method));
+ }
+ }
if (ffi_rettype != &ffi_type_void) {
ffi_ret = (void *)alloca(ffi_rettype->size);
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20080615/5077a07b/attachment.htm
More information about the macruby-changes
mailing list