From 9d1b612d4f457b2f3dda2d57f3044ab7a63670a9 Mon Sep 17 00:00:00 2001 From: Laurent Sansonetti Date: Fri, 25 Jun 2010 00:57:38 +0000 Subject: [PATCH] aot: precompiling BridgeSupport metadata (work in progress) git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@4272 23306eb0-4c56-4727-a40e-e92c0eb68959 --- bin/rubyc | 34 ++-- compiler.cpp | 436 ++++++++++++++++++++------------------------ compiler.h | 16 +- include/ruby/ruby.h | 2 +- objc.h | 6 + objc.m | 70 +++++++ ruby.c | 16 ++ vm.cpp | 20 +- 8 files changed, 348 insertions(+), 252 deletions(-) diff --git a/bin/rubyc b/bin/rubyc index 18d934b71..7e677abb9 100644 --- a/bin/rubyc +++ b/bin/rubyc @@ -13,17 +13,17 @@ class Compiler VALID_ARCHS = ['i386', 'x86_64'] def initialize(argv) - @mode = :normal @archs = [] @internal = argv.delete('--internal') + @frameworks = %w{Foundation} # Parse arguments. OptionParser.new do |opts| opts.banner = "Usage: #{NAME} [options] file..." opts.on('-c', 'Compile and assemble, but do not link') { @dont_link = true } opts.on('-o ', 'Place the output into ') { |output| @output = output } - #opts.on('--mode [MODE]', "Select compilation mode (normal or full)") { |mode| @mode = mode.intern } opts.on('--static', "Create a standalone static executable") { @static = true } + opts.on('--framework ', "Link standalone static executable with given framework") { |p| @frameworks << p } opts.on('--dylib', "Create a dynamic library") { @dylib = true } opts.on('-C', 'Compile, assemble and link a loadable object file') { @bundle = true } opts.on('-a', '--arch ', 'Compile for specified CPU architecture') { |arch| @archs << arch } @@ -37,9 +37,6 @@ class Compiler end die opts if argv.empty? @files = argv - if @mode != :normal and @mode != :full - die "Invalid mode `#{@mode}'. Possible choices are: normal, full" - end @archs.uniq! @archs << RUBY_ARCH if @archs.empty? @archs.each do |arch| @@ -47,6 +44,7 @@ class Compiler die "Invalid CPU architecture `#{arch}'. Possible values are: " + VALID_ARCHS.join(", ") end end + @frameworks.uniq! end # Locate necessary programs. @@ -76,8 +74,19 @@ class Compiler end def run - if @mode == :full - die "Full compilation mode is not implemented yet!" + @uses_bs_flags = '' + @frameworks.each do |f| + p = + if File.exist?(f) + "#{f}/Resources/BridgeSupport/#{File.basename(f)}Full.bridgesupport" + else + "/System/Library/Frameworks/#{f}.framework/Resources/BridgeSupport/#{f}Full.bridgesupport" + end + if File.exist?(p) + @uses_bs_flags << "--uses-bs #{p} " + else + die "Couldn't locate the Full BridgeSupport file for framework: `%{f}'" + end end if @dont_link or @bundle die "Cannot specify --static when not building an executable" if @static @@ -138,7 +147,7 @@ class Compiler @archs.each do |arch| # Compile the file into LLVM bitcode. bc = gen_tmpfile(base + arch, 'bc') - execute("arch -#{arch} #{@macruby} --emit-llvm \"#{bc}\" #{init_func} \"#{path}\"") + execute("arch -#{arch} #{@macruby} #{@uses_bs_flags} --emit-llvm \"#{bc}\" #{init_func} \"#{path}\"") # Compile the bitcode as assembly. asm = gen_tmpfile(base + arch, 's') @@ -239,7 +248,8 @@ EOS main_txt << <second; } - return gvar; + Value *idxs[] = { + ConstantInt::get(Int32Ty, 0), + ConstantInt::get(Int32Ty, 0) + }; + return GetElementPtrInst::Create(gvar, idxs, idxs + 2, "", bb); } -GlobalVariable * +Instruction * RoxorCompiler::compile_const_global_string(const char *str, const size_t len) { @@ -601,7 +605,11 @@ RoxorCompiler::compile_const_global_string(const char *str, gvar = iter->second; } - return gvar; + Value *idxs[] = { + ConstantInt::get(Int32Ty, 0), + ConstantInt::get(Int32Ty, 0) + }; + return GetElementPtrInst::Create(gvar, idxs, idxs + 2, "", bb); } Value * @@ -630,6 +638,24 @@ RoxorAOTCompiler::compile_ccache(ID name) return new LoadInst(gvar, "", bb); } +static void +discover_stubs(std::map *> &map, + std::vector &dest, SEL sel) +{ + std::map *>::iterator iter; + iter = map.find(sel); + if (iter != map.end()) { + std::vector *v = iter->second; + for (std::vector::iterator i = v->begin(); + i != v->end(); ++i) { + std::string s = *i; + if (std::find(dest.begin(), dest.end(), s) == dest.end()) { + dest.push_back(s); + } + } + } +} + Value * RoxorAOTCompiler::compile_sel(SEL sel, bool add_to_bb) { @@ -641,6 +667,9 @@ RoxorAOTCompiler::compile_sel(SEL sel, bool add_to_bb) ""); assert(gvar != NULL); sels[sel] = gvar; + + discover_stubs(bs_c_stubs_types, c_stubs, sel); + discover_stubs(bs_objc_stubs_types, objc_stubs, sel); } else { gvar = iter->second; @@ -773,12 +802,7 @@ RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel, 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) - }; - params.push_back(GetElementPtrInst::Create(gvar, idxs, idxs + 2, "", bb)); + params.push_back(compile_const_global_string(types)); Function *stub = compile_objc_stub(func, NULL, arity, types); params.push_back(new BitCastInst(stub, PtrTy, "", bb)); params.push_back(compile_const_pointer(NULL)); @@ -2278,7 +2302,7 @@ RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc, Instruction * RoxorCompiler::compile_range(Value *beg, Value *end, bool exclude_end, - bool retain, bool add_to_bb) + bool retain) { if (newRangeFunc == NULL) { // VALUE rb_range_new2(VALUE beg, VALUE end, int exclude_end, @@ -2295,10 +2319,7 @@ RoxorCompiler::compile_range(Value *beg, Value *end, bool exclude_end, ConstantInt::get(Int32Ty, exclude_end ? 1 : 0), ConstantInt::get(Int32Ty, retain ? 1 : 0) }; - if (add_to_bb) { - return compile_protected_call(newRangeFunc, args, args + 4); - } - return CallInst::Create(newRangeFunc, args, args + 4, ""); + return compile_protected_call(newRangeFunc, args, args + 4); } Value * @@ -2325,16 +2346,6 @@ RoxorCompiler::compile_literal(VALUE val) assert(cstr_len > 0); - GlobalVariable *str_gvar = compile_const_global_string(cstr, - cstr_len); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(str_gvar, - idxs, idxs + 2, "", bb); - if (newString2Func == NULL) { newString2Func = cast( module->getOrInsertFunction( @@ -2343,7 +2354,7 @@ RoxorCompiler::compile_literal(VALUE val) } Value *args[] = { - load, + compile_const_global_string(cstr, cstr_len), ConstantInt::get(Int32Ty, cstr_len) }; return CallInst::Create(newString2Func, args, args + 2, "", bb); @@ -4689,12 +4700,26 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) { Value *val = compile_node(node); assert(Function::classof(val)); - Function *function = cast(val); - function->setLinkage(GlobalValue::ExternalLinkage); + Function *func = cast(val); + func->setLinkage(GlobalValue::ExternalLinkage); - BasicBlock::InstListType &list = - function->getEntryBlock().getInstList(); - bb = &function->getEntryBlock(); + Function *init_func = compile_init_function(); + BasicBlock::InstListType &list = func->getEntryBlock().getInstList(); + list.insert(list.begin(), CallInst::Create(init_func, "")); + + return func; +} + +Function * +RoxorAOTCompiler::compile_init_function(void) +{ + reset_compiler_state(); + + FunctionType *ft = FunctionType::get(VoidTy, false); + Function *f = Function::Create(ft, GlobalValue::InternalLinkage, + "init_func", module); + + bb = BasicBlock::Create(context, "MainBlock", f); // Compile constant caches. @@ -4703,29 +4728,15 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) PtrTy, PtrTy, NULL)); for (std::map::iterator i = ccaches.begin(); - i != ccaches.end(); - ++i) { + i != ccaches.end(); + ++i) { ID name = i->first; GlobalVariable *gvar = i->second; - GlobalVariable *const_gvar = - compile_const_global_string(rb_id2name(name)); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(const_gvar, idxs, - idxs + 2, ""); - - Instruction *call = CallInst::Create(getConstCacheFunc, load, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + Value *val = CallInst::Create(getConstCacheFunc, + compile_const_global_string(rb_id2name(name)), "", bb); + new StoreInst(val, gvar, "", bb); } // Compile selectors. @@ -4733,32 +4744,16 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) Function *registerSelFunc = get_function("sel_registerName"); for (std::map::iterator i = sels.begin(); - i != sels.end(); - ++i) { + i != sels.end(); + ++i) { SEL sel = i->first; GlobalVariable *gvar = i->second; - GlobalVariable *sel_gvar = - compile_const_global_string(sel_getName(sel)); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(sel_gvar, idxs, idxs + 2, - ""); - - Instruction *call = CallInst::Create(registerSelFunc, load, ""); - - Instruction *cast = new BitCastInst(call, PtrTy, ""); - - Instruction *assign = new StoreInst(cast, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), cast); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + Value *val = CallInst::Create(registerSelFunc, + compile_const_global_string(sel_getName(sel)), "", bb); + val = new BitCastInst(val, PtrTy, "", bb); + new StoreInst(val, gvar, "", bb); } // Compile literals. @@ -4787,30 +4782,16 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) VALUE val = i->first; GlobalVariable *gvar = i->second; + Value *lit_val = NULL; switch (TYPE(val)) { case T_CLASS: { // This strange literal seems to be only emitted for // `for' loops. - GlobalVariable *kname_gvar = - compile_const_global_string(class_getName((Class)val)); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(kname_gvar, - idxs, idxs + 2, ""); - - Instruction *call = CallInst::Create(getClassFunc, - load, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + const char *cname = class_getName((Class)val); + lit_val = CallInst::Create(getClassFunc, + compile_const_global_string(cname), "", bb); } break; @@ -4827,15 +4808,8 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) PointerType::getUnqual(Int16Ty)); } else { - GlobalVariable *re_name_gvar = - compile_const_global_ustring(chars, chars_len); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - re_str = GetElementPtrInst::Create(re_name_gvar, - idxs, idxs + 2, ""); + re_str = compile_const_global_ustring(chars, + chars_len); } Value *args[] = { @@ -4843,67 +4817,24 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) ConstantInt::get(Int32Ty, chars_len), ConstantInt::get(Int32Ty, rb_reg_options(val)) }; - Instruction *call = CallInst::Create(newRegexp2Func, - args, args + 3, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - Instruction *re_str_insn = dyn_cast(re_str); - if (re_str_insn != NULL) { - list.insert(list.begin(), re_str_insn); - } + lit_val = CallInst::Create(newRegexp2Func, args, args + 3, + "", bb); } break; case T_SYMBOL: { const char *symname = rb_id2name(SYM2ID(val)); - - GlobalVariable *symname_gvar = - compile_const_global_string(symname); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(symname_gvar, - idxs, idxs + 2, ""); - - Instruction *call = CallInst::Create(name2symFunc, - load, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + lit_val = CallInst::Create(name2symFunc, + compile_const_global_string(symname), "", bb); } break; case T_BIGNUM: { const char *bigstr = RSTRING_PTR(rb_big2str(val, 10)); - - GlobalVariable *bigstr_gvar = - compile_const_global_string(bigstr); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(bigstr_gvar, - idxs, idxs + 2, ""); - - Instruction *call = CallInst::Create(newBignumFunc, - load, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + lit_val = CallInst::Create(newBignumFunc, + compile_const_global_string(bigstr), "", bb); } break; @@ -4913,15 +4844,9 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) bool exclude_end = false; rb_range_extract(val, &beg, &end, &exclude_end); - Instruction *call = compile_range( - ConstantInt::get(RubyObjTy, beg), + lit_val = compile_range(ConstantInt::get(RubyObjTy, beg), ConstantInt::get(RubyObjTy, end), - exclude_end, true, false); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); + exclude_end, true); } else { printf("unrecognized literal `%s' (class `%s' type %d)\n", @@ -4932,33 +4857,9 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) } break; } - } - - // Compile global entries. - Function *globalEntryFunc = cast(module->getOrInsertFunction( - "rb_global_entry", - PtrTy, IntTy, NULL)); - - for (std::map::iterator i = global_entries.begin(); - i != global_entries.end(); - ++i) { - - ID name_id = i->first; - GlobalVariable *gvar = i->second; - - Value *name_val = compile_id(name_id); - assert(Instruction::classof(name_val)); - Instruction *name = cast(name_val); - name->removeFromParent(); - - Instruction *call = CallInst::Create(globalEntryFunc, name, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), name); + assert(lit_val != NULL); + new StoreInst(lit_val, gvar, "", bb); } // Compile IDs. @@ -4968,55 +4869,47 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) IntTy, PtrTy, NULL)); for (std::map::iterator i = ids.begin(); - i != ids.end(); - ++i) { + i != ids.end(); + ++i) { ID name = i->first; GlobalVariable *gvar = i->second; - GlobalVariable *name_gvar = - compile_const_global_string(rb_id2name(name)); + Value *val = CallInst::Create(rbInternFunc, + compile_const_global_string(rb_id2name(name)), "", bb); + new StoreInst(val, gvar, "", bb); + } - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(name_gvar, idxs, - idxs + 2, ""); + // Compile global entries. - Instruction *call = CallInst::Create(rbInternFunc, load, ""); + Function *globalEntryFunc = cast(module->getOrInsertFunction( + "rb_global_entry", + PtrTy, IntTy, NULL)); - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + for (std::map::iterator i = global_entries.begin(); + i != global_entries.end(); + ++i) { + + ID name = i->first; + GlobalVariable *gvar = i->second; + + Value *val = CallInst::Create(rbInternFunc, + compile_const_global_string(rb_id2name(name)), "", bb); + val = CallInst::Create(globalEntryFunc, val, "", bb); + new StoreInst(val, gvar, "", bb); } // Compile constant class references. for (std::vector::iterator i = class_gvars.begin(); - i != class_gvars.end(); - ++i) { + i != class_gvars.end(); + ++i) { GlobalVariable *gvar = *i; - - GlobalVariable *str = compile_const_global_string( - gvar->getName().str().c_str()); - - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(str, idxs, idxs + 2, ""); - - Instruction *call = CallInst::Create(getClassFunc, load, ""); - - Instruction *assign = new StoreInst(call, gvar, ""); - - list.insert(list.begin(), assign); - list.insert(list.begin(), call); - list.insert(list.begin(), load); + Value *val = CallInst::Create(getClassFunc, + compile_const_global_string(gvar->getName().str().c_str()), + "",bb); + new StoreInst(val, gvar, "", bb); } // Instance variable slots. @@ -5026,21 +4919,56 @@ RoxorAOTCompiler::compile_main_function(NODE *node, bool *can_be_interpreted) PtrTy, NULL)); for (std::vector::iterator i = ivar_slots.begin(); - i != ivar_slots.end(); - ++i) { + i != ivar_slots.end(); + ++i) { GlobalVariable *gvar = *i; + Value *val = CallInst::Create(ivarSlotAlloc, "", bb); + new StoreInst(val, gvar, "", bb); + } + + // Stubs. - Instruction *call = CallInst::Create(ivarSlotAlloc, ""); - Instruction *assign = new StoreInst(call, gvar, ""); + Function *addStub = cast(module->getOrInsertFunction( + "rb_vm_add_stub", VoidTy, PtrTy, PtrTy, Int8Ty, NULL)); - list.insert(list.begin(), assign); - list.insert(list.begin(), call); + for (std::vector::iterator i = c_stubs.begin(); + i != c_stubs.end(); + ++i) { + + const char *types = i->c_str(); + try { + Value *args[] = { + compile_const_global_string(types), + new BitCastInst(compile_stub(types, false, TypeArity(types), + false), PtrTy, "", bb), + ConstantInt::get(Int8Ty, 0) + }; + CallInst::Create(addStub, args, args + 3, "", bb); + } + catch (...) {} } - bb = NULL; + for (std::vector::iterator i = objc_stubs.begin(); + i != objc_stubs.end(); + ++i) { - return function; + const char *types = i->c_str(); + try { + Value *args[] = { + compile_const_global_string(types), + new BitCastInst(compile_stub(types, false, + TypeArity(types) - 2, true), PtrTy, "", bb), + ConstantInt::get(Int8Ty, 1) + }; + CallInst::Create(addStub, args, args + 3, "", bb); + } + catch (...) {} + } + + ReturnInst::Create(context, bb); + + return f; } Function * @@ -5520,16 +5448,8 @@ RoxorCompiler::compile_new_pointer(const char *type, Value *val) "rb_vm_new_pointer", RubyObjTy, PtrTy, PtrTy, NULL)); } - GlobalVariable *gvar = compile_const_global_string(type); - Value *idxs[] = { - ConstantInt::get(Int32Ty, 0), - ConstantInt::get(Int32Ty, 0) - }; - Instruction *load = GetElementPtrInst::Create(gvar, idxs, idxs + 2, - "", bb); - Value *args[] = { - load, + compile_const_global_string(type), val }; return CallInst::Create(newPointerFunc, args, args + 2, "", bb); @@ -5804,7 +5724,11 @@ Function * RoxorCompiler::compile_stub(const char *types, bool variadic, int min_argc, bool is_objc) { - Function *f; + save_compiler_state(); + reset_compiler_state(); + + Function *f = NULL; + try { if (is_objc) { // VALUE stub(IMP imp, VALUE self, SEL sel, int argc, VALUE *argv) @@ -5947,6 +5871,16 @@ RoxorCompiler::compile_stub(const char *types, bool variadic, int min_argc, free(buf); + } // try + catch (...) { + if (f != NULL) { + f->eraseFromParent(); + } + restore_compiler_state(); + throw; + } + + restore_compiler_state(); return f; } @@ -6695,4 +6629,36 @@ RoxorCompiler::compile_ff3(NODE *node) return pn; } +static void +add_stub_types_cb(SEL sel, const char *types, bool is_objc, void *ctx) +{ + RoxorAOTCompiler *compiler = (RoxorAOTCompiler *)ctx; + + std::map *> &map = + is_objc ? compiler->bs_objc_stubs_types : compiler->bs_c_stubs_types; + + std::map *>::iterator iter = map.find(sel); + std::vector *v; + if (iter == map.end()) { + v = new std::vector(); + map[sel] = v; + } + else { + v = iter->second; + } + v->push_back(types); +} + +extern "C" +void +rb_vm_parse_bs_full_file(const char *path, + void (*add_stub_types_cb)(SEL, const char *, bool, void *), + void *ctx); + +void +RoxorAOTCompiler::load_bs_full_file(const char *path) +{ + rb_vm_parse_bs_full_file(path, add_stub_types_cb, (void *)this); +} + #endif // !MACRUBY_STATIC diff --git a/compiler.h b/compiler.h index a643aadf3..403f6d766 100644 --- a/compiler.h +++ b/compiler.h @@ -377,17 +377,17 @@ class RoxorCompiler { return compile_const_pointer(sel, PtrTy); } virtual Value *compile_id(ID id); - GlobalVariable *compile_const_global_string(const char *str, + Instruction *compile_const_global_string(const char *str, const size_t str_len); - GlobalVariable *compile_const_global_string(const char *str) { + Instruction *compile_const_global_string(const char *str) { return compile_const_global_string(str, strlen(str)); } - GlobalVariable *compile_const_global_ustring(const UniChar *str, + Instruction *compile_const_global_ustring(const UniChar *str, const size_t str_len); Value *compile_arity(rb_vm_arity_t &arity); Instruction *compile_range(Value *beg, Value *end, bool exclude_end, - bool retain=false, bool add_to_bb=true); + bool retain=false); Value *compile_literal(VALUE val); virtual Value *compile_immutable_literal(VALUE val); virtual Value *compile_global_entry(NODE *node); @@ -442,6 +442,12 @@ class RoxorAOTCompiler : public RoxorCompiler { Function *compile_main_function(NODE *node, bool *can_be_interpreted); + // BridgeSupport metadata needed for AOT compilation. + std::map *> bs_c_stubs_types, + bs_objc_stubs_types; + + void load_bs_full_file(const char *path); + private: std::map ccaches; std::map sels; @@ -449,11 +455,13 @@ class RoxorAOTCompiler : public RoxorCompiler { std::map global_entries; std::vector ivar_slots; std::map literals; + std::vector c_stubs, objc_stubs; GlobalVariable *cObject_gvar; GlobalVariable *cStandardError_gvar; std::vector class_gvars; + Function *compile_init_function(void); Value *compile_ccache(ID id); Value *compile_sel(SEL sel, bool add_to_bb=true); void compile_prepare_method(Value *classVal, Value *sel, diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index eb7ed3f9a..4b39b224b 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -814,7 +814,7 @@ VALUE rb_equal(VALUE,VALUE); RUBY_EXTERN VALUE ruby_verbose, ruby_debug; // AOT compiler. -RUBY_EXTERN VALUE ruby_aot_compile, ruby_aot_init_func; +RUBY_EXTERN VALUE ruby_aot_compile, ruby_aot_init_func, ruby_aot_bs_files; // Debugger. RUBY_EXTERN VALUE ruby_debug_socket_path; diff --git a/objc.h b/objc.h index d66d0b6ca..346f918c0 100644 --- a/objc.h +++ b/objc.h @@ -223,6 +223,12 @@ void rb_objc_fix_relocatable_load_path(void); extern bool rb_objc_enable_ivar_set_kvo_notifications; +#if !defined(MACRUBY_STATIC) +void rb_vm_parse_bs_full_file(const char *path, + void (*add_stub_types_cb)(SEL, const char *, bool, void *), + void *ctx); +#endif + #if defined(__cplusplus) } #endif diff --git a/objc.m b/objc.m index 19faec201..cfd8b0417 100644 --- a/objc.m +++ b/objc.m @@ -814,3 +814,73 @@ +(id)protocolWithName:(NSString *)name return (id)objc_getProtocol([name UTF8String]); } @end + +#if !defined(MACRUBY_STATIC) +static NSString * +get_type(NSXMLElement *elem) +{ + NSXMLNode *node = nil; +#if __LP64__ + node = [elem attributeForName:@"type64"]; +#endif + if (node == nil) { + node = [elem attributeForName:@"type"]; + assert(node != nil); + } + return [node stringValue]; +} + +static void +add_stub_types(NSXMLElement *elem, + void (*add_stub_types_cb)(SEL, const char *, bool, void *), + void *ctx, + bool is_objc) +{ + NSXMLNode *name = [elem attributeForName:is_objc + ? @"selector" : @"name"]; + NSArray *ary = [elem elementsForName:@"retval"]; + assert([ary count] == 1); + NSXMLElement *retval = [ary objectAtIndex:0]; + NSMutableString *types = [NSMutableString new]; + [types appendString:get_type(retval)]; + if (is_objc) { + [types appendString:@"@:"]; // self, sel + } + ary = [elem elementsForName:@"arg"]; + for (NSXMLElement *a in ary) { + [types appendString:get_type(a)]; + } + NSString *sel_str = [name stringValue]; + if (!is_objc && [ary count] > 0) { + sel_str = [sel_str stringByAppendingString:@":"]; + } + SEL sel = sel_registerName([sel_str UTF8String]); + add_stub_types_cb(sel, [types UTF8String], is_objc, ctx); +} + +void +rb_vm_parse_bs_full_file(const char *path, + void (*add_stub_types_cb)(SEL, const char *, bool, void *), + void *ctx) +{ + NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]]; + NSError *err = nil; + NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL: url + options: 0 error: &err]; + if (doc == nil) { + NSLog(@"can't open BridgeSupport full file at path `%s': %@", + path, err); + exit(1); + } + NSXMLElement *root = [doc rootElement]; + + for (NSXMLElement *k in [root elementsForName:@"class"]) { + for (NSXMLElement *m in [k elementsForName:@"method"]) { + add_stub_types(m, add_stub_types_cb, ctx, true); + } + } + for (NSXMLElement *f in [root elementsForName:@"function"]) { + add_stub_types(f, add_stub_types_cb, ctx, false); + } +} +#endif diff --git a/ruby.c b/ruby.c index 5505b4a3f..d8e550925 100644 --- a/ruby.c +++ b/ruby.c @@ -36,6 +36,7 @@ VALUE ruby_verbose = Qfalse; VALUE ruby_debug_socket_path = Qfalse; VALUE ruby_aot_compile = Qfalse; VALUE ruby_aot_init_func = Qfalse; +VALUE ruby_aot_bs_files = Qnil; VALUE rb_progname = Qnil; static int uid, euid, gid, egid; @@ -715,6 +716,21 @@ proc_options(int argc, char **argv, struct cmdline_options *opt) argc--; argv++; argc--; argv++; } + else if (strcmp("uses-bs", s) == 0) { + // This option is not documented and only used by macrubyc. + // Users should use macrubyc and never call this option + // directly. + if (argc < 2) { + rb_raise(rb_eRuntimeError, + "expected 1 argument (complete BridgeSupport file ) for --uses-bs"); + } + if (ruby_aot_bs_files == Qnil) { + ruby_aot_bs_files = rb_ary_new(); + GC_RETAIN(ruby_aot_bs_files); + } + rb_ary_push(ruby_aot_bs_files, rb_str_new2(argv[1])); + argc--; argv++; + } else if (strcmp("debug-mode", s) == 0) { // This option is not documented and only used by macrubyd. // Users should use macrubyd and never call this option diff --git a/vm.cpp b/vm.cpp index 497ccf32f..d42207d41 100644 --- a/vm.cpp +++ b/vm.cpp @@ -2823,7 +2823,8 @@ RoxorCore::gen_stub(std::string types, bool variadic, int min_argc, void *stub; if (iter == stubs.end()) { #if MACRUBY_STATIC - printf("uncached stub %s\n", types.c_str()); + printf("uncached %s stub `%s'\n", is_objc ? "ObjC" : "C", + types.c_str()); abort(); #else Function *f = RoxorCompiler::shared->compile_stub(types.c_str(), @@ -3848,6 +3849,7 @@ rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node, } extern VALUE rb_progname; +extern "C" void rb_vm_aot_load_bs_files(VALUE); extern "C" void @@ -3859,6 +3861,15 @@ rb_vm_aot_compile(NODE *node) assert(ruby_aot_compile); assert(ruby_aot_init_func); + // Load the BridgeSupport files. + if (ruby_aot_bs_files != Qnil) { + for (int i = 0, count = RARRAY_LEN(ruby_aot_bs_files); i < count; + i++) { + ((RoxorAOTCompiler *)RoxorCompiler::shared)->load_bs_full_file( + RSTRING_PTR(RARRAY_AT(ruby_aot_bs_files, i))); + } + } + // Compile the program as IR. RoxorCompiler::shared->set_fname(RSTRING_PTR(rb_progname)); Function *f = RoxorCompiler::shared->compile_main_function(node, NULL); @@ -4640,6 +4651,13 @@ setup_builtin_stubs(void) GET_CORE()->insert_stub("#@:", (void *)builtin_ostub1, true); } +extern "C" +void +rb_vm_add_stub(const char *types, void *func, unsigned char is_objc) +{ + GET_CORE()->insert_stub(types, func, is_objc); +} + #if !defined(MACRUBY_STATIC) static IMP old_resolveClassMethod_imp = NULL; static IMP old_resolveInstanceMethod_imp = NULL;