[macruby-changes] [4255] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Sat Jun 19 20:31:06 PDT 2010


Revision: 4255
          http://trac.macosforge.org/projects/ruby/changeset/4255
Author:   lsansonetti at apple.com
Date:     2010-06-19 20:31:02 -0700 (Sat, 19 Jun 2010)
Log Message:
-----------
aot: when preparing methods, also pre-compile objc stubs (currently, only generic ones)

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-06-19 20:42:43 UTC (rev 4254)
+++ MacRuby/trunk/compiler.cpp	2010-06-20 03:31:02 UTC (rev 4255)
@@ -37,6 +37,110 @@
 llvm::Module *RoxorCompiler::module = NULL;
 RoxorCompiler *RoxorCompiler::shared = NULL;
 
+#define __save_state(type, var) \
+    type __old__##var = var
+
+#define __restore_state(var) \
+    var = __old__##var
+
+#define save_compiler_state() \
+    __save_state(unsigned int, current_line);\
+    __save_state(BasicBlock *, bb);\
+    __save_state(BasicBlock *, entry_bb);\
+    __save_state(ID, current_mid);\
+    __save_state(rb_vm_arity_t, current_arity);\
+    __save_state(ID, self_id);\
+    __save_state(Value *, current_self);\
+    __save_state(bool, current_block);\
+    __save_state(bool, current_block_chain);\
+    __save_state(Value *, current_var_uses);\
+    __save_state(Value *, running_block);\
+    __save_state(Value *, current_block_arg);\
+    __save_state(BasicBlock *, begin_bb);\
+    __save_state(BasicBlock *, rescue_invoke_bb);\
+    __save_state(BasicBlock *, rescue_rethrow_bb);\
+    __save_state(BasicBlock *, ensure_bb);\
+    __save_state(bool, current_rescue);\
+    __save_state(NODE *, current_block_node);\
+    __save_state(Function *, current_block_func);\
+    __save_state(Function *, current_non_block_func);\
+    __save_state(GlobalVariable *, current_opened_class);\
+    __save_state(bool, dynamic_class);\
+    __save_state(BasicBlock *, current_loop_begin_bb);\
+    __save_state(BasicBlock *, current_loop_body_bb);\
+    __save_state(BasicBlock *, current_loop_end_bb);\
+    __save_state(PHINode *, current_loop_exit_val);\
+    __save_state(int, return_from_block);\
+    __save_state(int, return_from_block_ids);\
+    __save_state(PHINode *, ensure_pn);\
+    __save_state(bool, block_declaration);\
+    __save_state(AllocaInst *, dispatch_argv);
+
+#define restore_compiler_state() \
+    __restore_state(current_line);\
+    __restore_state(bb);\
+    __restore_state(entry_bb);\
+    __restore_state(current_mid);\
+    __restore_state(current_arity);\
+    __restore_state(self_id);\
+    __restore_state(current_self);\
+    __restore_state(current_block);\
+    __restore_state(current_block_chain);\
+    __restore_state(current_var_uses);\
+    __restore_state(running_block);\
+    __restore_state(current_block_arg);\
+    __restore_state(begin_bb);\
+    __restore_state(rescue_invoke_bb);\
+    __restore_state(rescue_rethrow_bb);\
+    __restore_state(ensure_bb);\
+    __restore_state(current_rescue);\
+    __restore_state(current_block_node);\
+    __restore_state(current_block_func);\
+    __restore_state(current_non_block_func);\
+    __restore_state(current_opened_class);\
+    __restore_state(dynamic_class);\
+    __restore_state(current_loop_begin_bb);\
+    __restore_state(current_loop_body_bb);\
+    __restore_state(current_loop_end_bb);\
+    __restore_state(current_loop_exit_val);\
+    __restore_state(return_from_block);\
+    __restore_state(return_from_block_ids);\
+    __restore_state(ensure_pn);\
+    __restore_state(block_declaration);\
+    __restore_state(dispatch_argv);
+
+#define reset_compiler_state() \
+    bb = NULL;\
+    entry_bb = NULL;\
+    begin_bb = NULL;\
+    rescue_invoke_bb = NULL;\
+    rescue_rethrow_bb = NULL;\
+    ensure_bb = NULL;\
+    current_mid = 0;\
+    current_arity = rb_vm_arity(-1);\
+    self_id = rb_intern("self");\
+    current_self = NULL;\
+    current_var_uses = NULL;\
+    running_block = NULL;\
+    current_block_arg = NULL;\
+    current_block = false;\
+    current_block_chain = false;\
+    current_block_node = NULL;\
+    current_block_func = NULL;\
+    current_non_block_func = NULL;\
+    current_opened_class = NULL;\
+    dynamic_class = false;\
+    current_loop_begin_bb = NULL;\
+    current_loop_body_bb = NULL;\
+    current_loop_end_bb = NULL;\
+    current_loop_exit_val = NULL;\
+    current_rescue = false;\
+    return_from_block = -1;\
+    return_from_block_ids = 0;\
+    ensure_pn = NULL;\
+    block_declaration = false;\
+    dispatch_argv = NULL;
+
 RoxorCompiler::RoxorCompiler(bool _debug_mode)
 {
     assert(RoxorCompiler::module != NULL);
@@ -48,36 +152,7 @@
     inside_eval = false;
     current_line = 0;
 
-    bb = NULL;
-    entry_bb = NULL;
-    begin_bb = NULL;
-    rescue_invoke_bb = NULL;
-    rescue_rethrow_bb = NULL;
-    ensure_bb = NULL;
-    current_mid = 0;
-    current_arity = rb_vm_arity(-1);
-    self_id = rb_intern("self");
-    current_self = NULL;
-    current_var_uses = NULL;
-    running_block = NULL;
-    current_block_arg = NULL;
-    current_block = false;
-    current_block_chain = false;
-    current_block_node = NULL;
-    current_block_func = NULL;
-    current_non_block_func = NULL;
-    current_opened_class = NULL;
-    dynamic_class = false;
-    current_loop_begin_bb = NULL;
-    current_loop_body_bb = NULL;
-    current_loop_end_bb = NULL;
-    current_loop_exit_val = NULL;
-    current_rescue = false;
-    return_from_block = -1;
-    return_from_block_ids = 0;
-    ensure_pn = NULL;
-    block_declaration = false;
-    dispatch_argv = NULL;
+    reset_compiler_state();
 
     dispatchFunc = get_function("vm_dispatch");
     fastPlusFunc = get_function("vm_fast_plus");
@@ -667,28 +742,55 @@
 
 void
 RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel,
-	bool singleton, Function *new_function, rb_vm_arity_t &arity,
-	NODE *body)
+	bool singleton, Function *func, rb_vm_arity_t &arity, NODE *body)
 {
     if (prepareMethodFunc == NULL) {
 	// void rb_vm_prepare_method2(Class klass, unsigned char dynamic_class,
-	//	SEL sel, IMP ruby_imp, rb_vm_arity_t arity, int flags)
-	prepareMethodFunc = 
-	    cast<Function>(module->getOrInsertFunction(
-			"rb_vm_prepare_method2",
-			VoidTy, RubyObjTy, Int8Ty, PtrTy, PtrTy, Int64Ty,
-			Int32Ty, NULL));
+	//	SEL sel, IMP ruby_imp, rb_vm_arity_t arity, int flags, ...)
+	std::vector<const Type *> types;
+	types.push_back(RubyObjTy);
+	types.push_back(Int8Ty);
+	types.push_back(PtrTy);
+	types.push_back(PtrTy);
+	types.push_back(Int64Ty);
+	types.push_back(Int32Ty);
+	FunctionType *ft = FunctionType::get(VoidTy, types, true);
+	prepareMethodFunc = cast<Function>(module->getOrInsertFunction(
+		    "rb_vm_prepare_method2", ft));
     }
 
-    Value *args[] = {
-	classVal,
-	ConstantInt::get(Int8Ty, !singleton && dynamic_class ? 1 : 0),
-	sel,
-	new BitCastInst(new_function, PtrTy, "", bb),
-	compile_arity(arity),
-	ConstantInt::get(Int32Ty, rb_vm_node_flags(body))	
+    const unsigned char dyn_class = !singleton && dynamic_class ? 1 : 0;
+
+    std::vector<Value *> params;
+    params.push_back(classVal);
+    params.push_back(ConstantInt::get(Int8Ty, dyn_class));
+    params.push_back(sel);
+    params.push_back(new BitCastInst(func, PtrTy, "", bb));
+    params.push_back(compile_arity(arity));
+    params.push_back(ConstantInt::get(Int32Ty, rb_vm_node_flags(body)));
+
+    // Pre-compile a generic Objective-C stub, where all arguments and return
+    // value are Ruby types.
+    char types[100];
+    types[0] = '@';
+    types[1] = '@';
+    types[2] = ':';
+    assert(arity.real < (int)sizeof(types) - 3);
+    for (int i = 0; i < arity.real; i++) {
+	types[3 + i] = '@';
+    }
+    types[arity.real + 3] = '\0';
+    GlobalVariable *gvar = compile_const_global_string(types);
+    Value *idxs[] = {
+	ConstantInt::get(Int32Ty, 0),
+	ConstantInt::get(Int32Ty, 0)
     };
-    CallInst::Create(prepareMethodFunc, args, args + 6, "", bb);
+    params.push_back(GetElementPtrInst::Create(gvar, idxs, idxs + 2, "", bb));
+    Function *stub = compile_objc_stub(func, NULL, arity, types);
+    params.push_back(new BitCastInst(stub, PtrTy, "", bb));
+    params.push_back(compile_const_pointer(NULL));
+
+    CallInst::Create(prepareMethodFunc, params.begin(), params.end(), "", bb);
 }
 
 void
@@ -6106,6 +6208,9 @@
 {
     assert(ruby_func != NULL || ruby_imp != NULL);
 
+    save_compiler_state();
+    reset_compiler_state();
+
     const size_t buf_len = strlen(types) + 1;
     assert(buf_len > 1);
     char *buf = (char *)malloc(buf_len);
@@ -6276,6 +6381,8 @@
     rescue_invoke_bb = old_rescue_invoke_bb;
 #endif
 
+    restore_compiler_state();
+
     return f;
 }
 

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-06-19 20:42:43 UTC (rev 4254)
+++ MacRuby/trunk/compiler.h	2010-06-20 03:31:02 UTC (rev 4255)
@@ -115,9 +115,7 @@
 	Value *running_block;
 	Value *current_block_arg;
 	BasicBlock *begin_bb;
-	// block used in an invoke when an exception occurs
 	BasicBlock *rescue_invoke_bb;
-	// block to return to in a rescue if an exception is not handled
 	BasicBlock *rescue_rethrow_bb;
 	BasicBlock *ensure_bb;
 	bool current_rescue;

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-06-19 20:42:43 UTC (rev 4254)
+++ MacRuby/trunk/vm.cpp	2010-06-20 03:31:02 UTC (rev 4255)
@@ -1802,34 +1802,70 @@
 #endif
 }
 
-#if !defined(MACRUBY_STATIC)
+struct vm_objc_imp_type {
+    const char *types;
+    IMP imp;
+
+    vm_objc_imp_type(const char *_types, IMP _imp) {
+	types = _types;
+	imp = _imp;
+    }
+};
+
 rb_vm_method_node_t *
-RoxorCore::resolve_method(Class klass, SEL sel, Function *func,
-	const rb_vm_arity_t &arity, int flags, IMP imp, Method m)
+RoxorCore::resolve_method(Class klass, SEL sel, void *func,
+	const rb_vm_arity_t &arity, int flags, IMP imp, Method m,
+	void *objc_imp_types)
 {
+#if MACRUBY_STATIC
+    assert(imp != NULL);
+#else
     if (imp == NULL) {
 	// Compile if necessary.
 	assert(func != NULL);
-	imp = compile(func);
+	imp = compile((Function *)func);
     }
+#endif
 
     // Resolve Objective-C signature.
     const int types_count = arity.real + 3; // retval, self and sel
     char types[100];
     resolve_method_type(types, sizeof types, klass, m, sel, types_count);
 
+    // Retrieve previous-generated Objective-C stub if possible.
+    IMP objc_imp = NULL;
+    if (objc_imp_types != NULL) {
+	std::vector<vm_objc_imp_type> *v =
+	    (std::vector<vm_objc_imp_type> *)objc_imp_types;
+
+	for (std::vector<vm_objc_imp_type>::iterator i = v->begin();
+		i != v->end(); ++i) {
+	    if (strcmp(types, i->types) == 0) {
+		objc_imp = i->imp;
+		break;
+	    }
+	}
+    }
+
+#if MACRUBY_STATIC
+    if (objc_imp == NULL) {
+	printf("can't define method `%s' because no Objective-C stub was pre-compiled", sel_getName(sel));
+	abort();
+    }
+#else
     // Generate Objective-C stub if needed.
-    std::map<IMP, IMP>::iterator iter = objc_to_ruby_stubs.find(imp);
-    IMP objc_imp;
-    if (iter == objc_to_ruby_stubs.end()) {
-	Function *objc_func = RoxorCompiler::shared->compile_objc_stub(func,
-		imp, arity, types);
-	objc_imp = compile(objc_func);
-	objc_to_ruby_stubs[imp] = objc_imp;
+    if (objc_imp == NULL) {
+	std::map<IMP, IMP>::iterator iter = objc_to_ruby_stubs.find(imp);
+	if (iter == objc_to_ruby_stubs.end()) {
+	    Function *objc_func = RoxorCompiler::shared->compile_objc_stub(
+		    (Function *)func, imp, arity, types);
+	    objc_imp = compile(objc_func);
+	    objc_to_ruby_stubs[imp] = objc_imp;
+	}
+	else {
+	    objc_imp = iter->second;
+	}
     }
-    else {
-	objc_imp = iter->second;
-    }
 
     // Delete the selector from the not-yet-JIT'ed cache if needed.
     std::multimap<Class, SEL>::iterator iter2, last2;
@@ -1844,11 +1880,13 @@
 	    ++iter2;
 	}
     }
+#endif
 
     // Finally, add the method.
     return add_method(klass, sel, objc_imp, imp, arity, flags, types);
 }
 
+#if !defined(MACRUBY_STATIC)
 bool
 RoxorCore::resolve_methods(std::map<Class, rb_vm_method_source_t *> *map,
 	Class klass, SEL sel)
@@ -1864,7 +1902,7 @@
 	if (k != NULL) {
 	    rb_vm_method_source_t *m = iter->second;
 	    resolve_method(iter->first, sel, m->func, m->arity, m->flags,
-		    NULL, NULL);
+		    NULL, NULL, NULL);
 	    map->erase(iter++);
 	    free(m);
 	    did_something = true;
@@ -1961,7 +1999,8 @@
 
 static void
 prepare_method(Class klass, bool dynamic_class, SEL sel, void *data,
-	const rb_vm_arity_t &arity, int flags, bool precompiled)
+	const rb_vm_arity_t &arity, int flags, bool precompiled,
+	void *objc_imp_types)
 {
     if (dynamic_class) {
 	Class k = GET_VM()->get_current_class();
@@ -2000,30 +2039,26 @@
 
 prepare_method:
 
-#if MACRUBY_STATIC
     m = class_getInstanceMethod(klass, sel);
-    assert(m != NULL);
-
-    assert(precompiled);
-
-    if (imp == NULL) {
-	imp = (IMP)data;
-    }
-    //XXX GET_CORE()->resolve_method(klass, sel, NULL, arity, flags, imp, m);
-#else
-    m = class_getInstanceMethod(klass, sel);
+#if !defined(MACRUBY_STATIC)
     if (m == NULL && rb_vm_resolve_method(klass, sel)) {
 	m = class_getInstanceMethod(klass, sel);
 	assert(m != NULL);
     }
+#endif
 
     if (precompiled) {
 	if (imp == NULL) {
 	    imp = (IMP)data;
 	}
-	GET_CORE()->resolve_method(klass, sel, NULL, arity, flags, imp, m);
+	assert(objc_imp_types != NULL);
+	GET_CORE()->resolve_method(klass, sel, NULL, arity, flags, imp, m,
+		objc_imp_types);
     }
     else {
+#if MACRUBY_STATIC
+	abort();
+#else
 	Function *func = (Function *)data;
 	if (m != NULL || custom_resolver) {
 	    // The method already exists _or_ the class implemented a custom
@@ -2031,14 +2066,15 @@
 	    if (imp == NULL) {
 		imp = GET_CORE()->compile(func);
 	    }
-	    GET_CORE()->resolve_method(klass, sel, func, arity, flags, imp, m);
+	    GET_CORE()->resolve_method(klass, sel, func, arity, flags, imp, m,
+		    objc_imp_types);
 	}
 	else {
 	    // Let's keep the method and JIT it later on demand.
 	    GET_CORE()->prepare_method(klass, sel, func, arity, flags);
 	}
+#endif
     }
-#endif
 
     if (!redefined) {
 	char buf[100];
@@ -2083,7 +2119,7 @@
 		VALUE mod = RARRAY_AT(included_in_classes, i);
 		rb_vm_set_current_scope(mod, SCOPE_PUBLIC);
 		prepare_method((Class)mod, false, orig_sel, data, arity,
-			flags, precompiled);
+			flags, precompiled, objc_imp_types);
 		rb_vm_set_current_scope(mod, SCOPE_DEFAULT);
 	    }
 	}
@@ -2107,17 +2143,32 @@
 	Function *func, const rb_vm_arity_t arity, int flags)
 {
     prepare_method(klass, dynamic_class, sel, (void *)func, arity,
-	    flags, false);
+	    flags, false, NULL);
 }
 #endif
 
 extern "C"
 void
 rb_vm_prepare_method2(Class klass, unsigned char dynamic_class, SEL sel,
-	IMP ruby_imp, const rb_vm_arity_t arity, int flags)
+	IMP ruby_imp, const rb_vm_arity_t arity, int flags, ...)
 {
+    std::vector<vm_objc_imp_type> v;
+    va_list ar;
+    va_start(ar, flags);
+    do {
+	const char *types = va_arg(ar, const char *);
+	if (types == NULL) {
+	    break;
+	}
+	IMP imp = va_arg(ar, IMP);
+	assert(imp != NULL);
+	v.push_back(vm_objc_imp_type(types, imp));
+    }
+    while (true);
+    va_end(ar);
+
     prepare_method(klass, dynamic_class, sel, (void *)ruby_imp, arity,
-	    flags, true);
+	    flags, true, (void *)&v);
 }
 
 #define VISI(x) ((x)&NOEX_MASK)
@@ -2350,7 +2401,7 @@
 	    // JIT it.
 	    IMP imp = GET_CORE()->compile(m_src->func);
 	    resolve_method(to_class, sel, m_src->func, m_src->arity,
-		    m_src->flags, imp, m);
+		    m_src->flags, imp, m, NULL);
 	}
 	else {
 #if ROXOR_VM_DEBUG

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-06-19 20:42:43 UTC (rev 4254)
+++ MacRuby/trunk/vm.h	2010-06-20 03:31:02 UTC (rev 4255)
@@ -730,7 +730,9 @@
 	// Maps to cache compiled stubs for a given Objective-C runtime type.
 	std::map<std::string, void *> c_stubs, objc_stubs,
 	    to_rval_convertors, to_ocval_convertors;
+#if !defined(MACRUBY_STATIC)
 	std::map<IMP, IMP> objc_to_ruby_stubs;
+#endif
 	std::map<int, void *> rb_large_arity_rstubs; // Large arity Ruby calls
 	std::map<int, void *> rb_large_arity_bstubs; // Large arity block calls
 
@@ -860,12 +862,12 @@
 
 	void prepare_method(Class klass, SEL sel, Function *func,
 		const rb_vm_arity_t &arity, int flag);
-	rb_vm_method_node_t *resolve_method(Class klass, SEL sel,
-		Function *func, const rb_vm_arity_t &arity, int flags,
-		IMP imp, Method m);
 	bool resolve_methods(std::map<Class, rb_vm_method_source_t *> *map,
 		Class klass, SEL sel);
 #endif
+	rb_vm_method_node_t *resolve_method(Class klass, SEL sel,
+		void *func, const rb_vm_arity_t &arity, int flags,
+		IMP imp, Method m, void *objc_imp_types);
 	rb_vm_method_node_t *add_method(Class klass, SEL sel, IMP imp,
 		IMP ruby_imp, const rb_vm_arity_t &arity, int flags,
 		const char *types);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100619/95b16750/attachment-0001.html>


More information about the macruby-changes mailing list