Revision: 1955 http://trac.macosforge.org/projects/ruby/changeset/1955 Author: lsansonetti@apple.com Date: 2009-06-30 23:28:35 -0700 (Tue, 30 Jun 2009) Log Message: ----------- AOT compiler: added support for blocks Modified Paths: -------------- MacRuby/branches/experimental/compiler.cpp MacRuby/branches/experimental/compiler.h MacRuby/branches/experimental/vm.cpp MacRuby/branches/experimental/vm.h MacRuby/branches/experimental/vm_eval.c Modified: MacRuby/branches/experimental/compiler.cpp =================================================================== --- MacRuby/branches/experimental/compiler.cpp 2009-06-30 20:34:22 UTC (rev 1954) +++ MacRuby/branches/experimental/compiler.cpp 2009-07-01 06:28:35 UTC (rev 1955) @@ -551,6 +551,15 @@ params.end(), "", bb); } +inline Value * +RoxorCompiler::compile_arity(rb_vm_arity_t &arity) +{ + uint64_t v; + assert(sizeof(uint64_t) == sizeof(rb_vm_arity_t)); + memcpy(&v, &arity, sizeof(rb_vm_arity_t)); + return ConstantInt::get(Type::Int64Ty, v); +} + void RoxorAOTCompiler::compile_prepare_method(Value *classVal, Value *sel, Function *new_function, rb_vm_arity_t &arity, NODE *body) @@ -575,11 +584,7 @@ GET_CORE()->compile(new_function); params.push_back(new BitCastInst(new_function, PtrTy, "", bb)); - uint64_t v; - assert(sizeof(uint64_t) == sizeof(rb_vm_arity_t)); - memcpy(&v, &arity, sizeof(rb_vm_arity_t)); - params.push_back(ConstantInt::get(Type::Int64Ty, v)); - + params.push_back(compile_arity(arity)); params.push_back(ConstantInt::get(Type::Int32Ty, rb_vm_node_flags(body))); CallInst::Create(prepareMethodFunc, params.begin(), @@ -797,6 +802,21 @@ } Value * +RoxorCompiler::compile_prepare_block_args(Function *func, int *flags) +{ + return compile_const_pointer(func); +} + +Value * +RoxorAOTCompiler::compile_prepare_block_args(Function *func, int *flags) +{ + *flags |= VM_BLOCK_AOT; + // Force compilation (no stub). + GET_CORE()->compile(func); + return new BitCastInst(func, PtrTy, "", bb); +} + +Value * RoxorCompiler::compile_block_create(NODE *node) { if (node != NULL) { @@ -815,14 +835,16 @@ assert(current_block_func != NULL && current_block_node != NULL); if (prepareBlockFunc == NULL) { - // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self, - // rb_vm_var_uses **parent_var_uses, - // rb_vm_block_t *parent_block, - // int dvars_size, ...); + // void *rb_vm_prepare_block(Function *func, int flags, VALUE self, + // rb_vm_arity_t arity, + // rb_vm_var_uses **parent_var_uses, + // rb_vm_block_t *parent_block, + // int dvars_size, ...); std::vector<const Type *> types; types.push_back(PtrTy); - types.push_back(PtrTy); + types.push_back(Type::Int32Ty); types.push_back(RubyObjTy); + types.push_back(Type::Int64Ty); types.push_back(PtrPtrTy); types.push_back(PtrTy); types.push_back(Type::Int32Ty); @@ -832,22 +854,20 @@ } std::vector<Value *> params; - params.push_back(compile_const_pointer(current_block_func)); - params.push_back(compile_const_pointer(current_block_node)); + int flags = 0; + params.push_back(compile_prepare_block_args(current_block_func, &flags)); + if (nd_type(current_block_node) == NODE_SCOPE + && current_block_node->nd_body == NULL) { + flags |= VM_BLOCK_EMPTY; + } + params.push_back(ConstantInt::get(Type::Int32Ty, flags)); params.push_back(current_self); - if (current_var_uses == NULL) { - // there is no local variables in this scope - params.push_back(compile_const_pointer_to_pointer(NULL)); - } - else { - params.push_back(current_var_uses); - } - if (running_block == NULL) { - params.push_back(compile_const_pointer(NULL)); - } - else { - params.push_back(running_block); - } + rb_vm_arity_t arity = rb_vm_node_arity(current_block_node); + params.push_back(compile_arity(arity)); + params.push_back(current_var_uses == NULL + ? compile_const_pointer_to_pointer(NULL) : current_var_uses); + params.push_back(running_block == NULL + ? compile_const_pointer(NULL) : running_block); // Dvars. params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size())); @@ -3385,7 +3405,8 @@ } else { blockVal = block_given - ? compile_block_create() : compile_const_pointer(NULL); + ? compile_block_create(NULL) + : compile_const_pointer(NULL); } params[3] = blockVal; @@ -4172,7 +4193,7 @@ params.push_back(compile_mcache(selEach, false)); params.push_back(compile_node(node->nd_iter)); params.push_back(compile_sel(selEach)); - params.push_back(compile_block_create()); + params.push_back(compile_block_create(NULL)); params.push_back(ConstantInt::get(Type::Int8Ty, 0)); params.push_back(ConstantInt::get(Type::Int32Ty, 0)); Modified: MacRuby/branches/experimental/compiler.h =================================================================== --- MacRuby/branches/experimental/compiler.h 2009-06-30 20:34:22 UTC (rev 1954) +++ MacRuby/branches/experimental/compiler.h 2009-07-01 06:28:35 UTC (rev 1955) @@ -202,7 +202,8 @@ Value *compile_when_splat(Value *comparedToVal, Value *splatVal); Value *compile_fast_eqq_call(Value *selfVal, Value *comparedToVal); Value *compile_attribute_assign(NODE *node, Value *extra_val); - Value *compile_block_create(NODE *node=NULL); + virtual Value *compile_prepare_block_args(Function *func, int *flags); + Value *compile_block_create(NODE *node); Value *compile_binding(void); Value *compile_optimized_dispatch_call(SEL sel, int argc, std::vector<Value *> ¶ms); @@ -230,6 +231,7 @@ } virtual Value *compile_id(ID id); GlobalVariable *compile_const_global_string(const char *str); + Value *compile_arity(rb_vm_arity_t &arity); void compile_landing_pad_header(void); void compile_landing_pad_footer(void); @@ -301,6 +303,7 @@ Instruction *compile_sel(SEL sel, bool add_to_bb=true); void compile_prepare_method(Value *classVal, Value *sel, Function *new_function, rb_vm_arity_t &arity, NODE *body); + Value *compile_prepare_block_args(Function *func, int *flags); Value *compile_nsobject(void); Value *compile_id(ID id); Modified: MacRuby/branches/experimental/vm.cpp =================================================================== --- MacRuby/branches/experimental/vm.cpp 2009-06-30 20:34:22 UTC (rev 1954) +++ MacRuby/branches/experimental/vm.cpp 2009-07-01 06:28:35 UTC (rev 1955) @@ -242,15 +242,13 @@ parse_in_eval = false; } -static inline NODE * -block_cache_key(NODE *node) +static inline void * +block_cache_key(const rb_vm_block_t *b) { - if (nd_type(node) == NODE_IFUNC) { - // In this case, node is dynamic but fortunately u1.node is always - // unique (it contains the IMP) - return node->u1.node; + if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) { + return (void *)b->imp; } - return node; + return (void *)b->userdata; } RoxorVM::RoxorVM(const RoxorVM &vm) @@ -261,6 +259,7 @@ std::vector<rb_vm_block_t *> &vm_blocks = const_cast<RoxorVM &>(vm).current_blocks; + for (std::vector<rb_vm_block_t *>::iterator i = vm_blocks.begin(); (i + 1) != vm_blocks.end(); ++i) { @@ -280,13 +279,11 @@ memcpy(b, orig, block_size); GC_WB(&b->self, orig->self); - GC_WB(&b->node, orig->node); GC_WB(&b->locals, orig->locals); GC_WB(&b->parent_block, orig->parent_block); // XXX not sure #endif rb_objc_retain(b); - NODE *key = block_cache_key(orig->node); - blocks[key] = b; + blocks[block_cache_key(orig)] = b; } current_blocks.push_back(b); } @@ -2913,9 +2910,9 @@ } rb_vm_block_t * -RoxorVM::uncache_or_create_block(NODE *key, bool *cached, int dvars_size) +RoxorVM::uncache_or_create_block(void *key, bool *cached, int dvars_size) { - std::map<NODE *, rb_vm_block_t *>::iterator iter = blocks.find(key); + std::map<void *, rb_vm_block_t *>::iterator iter = blocks.find(key); rb_vm_block_t *b; @@ -2925,9 +2922,11 @@ if (iter != blocks.end()) { rb_objc_release(iter->second); } + b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t) + (sizeof(VALUE *) * dvars_size)); rb_objc_retain(b); + blocks[key] = b; *cached = false; } @@ -2941,40 +2940,44 @@ extern "C" rb_vm_block_t * -rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, +rb_vm_prepare_block(void *function, int flags, VALUE self, rb_vm_arity_t arity, rb_vm_var_uses **parent_var_uses, rb_vm_block_t *parent_block, int dvars_size, ...) { - NODE *cache_key = block_cache_key(node); + assert(function != NULL); bool cached = false; - rb_vm_block_t *b = GET_VM()->uncache_or_create_block(cache_key, &cached, + rb_vm_block_t *b = GET_VM()->uncache_or_create_block(function, &cached, dvars_size); if (!cached) { - if (nd_type(node) == NODE_IFUNC) { - assert(llvm_function == NULL); - b->imp = (IMP)node->u1.node; - memset(&b->arity, 0, sizeof(rb_vm_arity_t)); // not used + if ((flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) { + b->imp = (IMP)function; } else { - assert(llvm_function != NULL); - GET_CORE()->lock(); - b->imp = GET_CORE()->compile((Function *)llvm_function); - GET_CORE()->unlock(); - b->arity = rb_vm_node_arity(node); + if ((flags & VM_BLOCK_AOT) == VM_BLOCK_AOT) { + flags ^= VM_BLOCK_AOT; + b->imp = (IMP)function; + } + else { + GET_CORE()->lock(); + b->imp = GET_CORE()->compile((Function *)function); + GET_CORE()->unlock(); + } + b->userdata = (VALUE)function; } - b->flags = 0; + b->arity = arity; + b->flags = flags; b->dvars_size = dvars_size; b->parent_var_uses = NULL; b->parent_block = NULL; } else { assert(b->dvars_size == dvars_size); + assert((b->flags & flags) == flags); } b->self = self; - b->node = node; b->parent_var_uses = parent_var_uses; GC_WB(&b->parent_block, parent_block); @@ -3006,6 +3009,17 @@ } extern "C" +rb_vm_block_t * +rb_vm_create_block(IMP imp, VALUE self, VALUE userdata) +{ + rb_vm_block_t *b = rb_vm_prepare_block((void *)imp, VM_BLOCK_IFUNC, self, + rb_vm_arity(0), // not used + NULL, NULL, 0, 0); + GC_WB(&b->userdata, userdata); + return b; +} + +extern "C" void* rb_gc_read_weak_ref(void **referrer); @@ -3383,7 +3397,6 @@ rb_vm_block_t *b = (rb_vm_block_t *)xmalloc(sizeof(rb_vm_block_t)); GC_WB(&b->self, method->recv); - b->node = NULL; b->arity = method->node == NULL ? rb_vm_arity(method->arity) : method->node->arity; b->imp = (IMP)method; @@ -3424,24 +3437,18 @@ static inline VALUE rb_vm_block_eval0(rb_vm_block_t *b, VALUE self, int argc, const VALUE *argv) { - if (b->node != NULL) { - if (nd_type(b->node) == NODE_IFUNC) { - // Special case for blocks passed with rb_objc_block_call(), to - // preserve API compatibility. - VALUE data = (VALUE)b->node->u2.node; + if ((b->flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) { + // Special case for blocks passed with rb_objc_block_call(), to + // preserve API compatibility. + VALUE (*pimp)(VALUE, VALUE, int, const VALUE *) = + (VALUE (*)(VALUE, VALUE, int, const VALUE *))b->imp; - VALUE (*pimp)(VALUE, VALUE, int, const VALUE *) = - (VALUE (*)(VALUE, VALUE, int, const VALUE *))b->imp; - - return (*pimp)(argc == 0 ? Qnil : argv[0], data, argc, argv); - } - else if (nd_type(b->node) == NODE_SCOPE) { - if (b->node->nd_body == NULL) { - // Trying to call an empty block! - return Qnil; - } - } + return (*pimp)(argc == 0 ? Qnil : argv[0], b->userdata, argc, argv); } + else if ((b->flags & VM_BLOCK_EMPTY) == VM_BLOCK_EMPTY) { + // Trying to call an empty block! + return Qnil; + } rb_vm_arity_t arity = b->arity; Modified: MacRuby/branches/experimental/vm.h =================================================================== --- MacRuby/branches/experimental/vm.h 2009-06-30 20:34:22 UTC (rev 1954) +++ MacRuby/branches/experimental/vm.h 2009-07-01 06:28:35 UTC (rev 1955) @@ -30,10 +30,15 @@ #define VM_BLOCK_LAMBDA 0x0002 // block is a lambda #define VM_BLOCK_ACTIVE 0x0004 // block is active (being executed) #define VM_BLOCK_METHOD 0x0008 // block is created from Method +#define VM_BLOCK_IFUNC 0x0010 // block is created from rb_vm_create_block() +#define VM_BLOCK_EMPTY 0x0012 // block has an empty body +#define VM_BLOCK_AOT 0x1000 // block is created by the AOT compiler (temporary) + typedef struct rb_vm_block { VALUE self; - NODE *node; + VALUE userdata; // if VM_BLOCK_IFUNC, contains the user data, otherwise + // contains the key used in the blocks cache. rb_vm_arity_t arity; IMP imp; int flags; @@ -336,10 +341,7 @@ } void rb_vm_add_block_lvar_use(rb_vm_block_t *block); -rb_vm_block_t *rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, - struct rb_vm_var_uses **parent_lvar_uses, - rb_vm_block_t *parent_block, - int dvars_size, ...); +rb_vm_block_t *rb_vm_create_block(IMP imp, VALUE self, VALUE userdata); rb_vm_block_t *rb_vm_current_block(void); rb_vm_block_t *rb_vm_first_block(void); bool rb_vm_block_saved(void); @@ -730,7 +732,7 @@ private: // Cache to avoid allocating the same block twice. - std::map<NODE *, rb_vm_block_t *> blocks; + std::map<void *, rb_vm_block_t *> blocks; // Keeps track of the current VM state (blocks, exceptions, bindings). std::vector<rb_vm_block_t *> current_blocks; @@ -804,7 +806,7 @@ return b; } - rb_vm_block_t *uncache_or_create_block(NODE *key, bool *cached, + rb_vm_block_t *uncache_or_create_block(void *key, bool *cached, int dvars_size); rb_vm_binding_t *current_binding(void) { Modified: MacRuby/branches/experimental/vm_eval.c =================================================================== --- MacRuby/branches/experimental/vm_eval.c 2009-06-30 20:34:22 UTC (rev 1954) +++ MacRuby/branches/experimental/vm_eval.c 2009-07-01 06:28:35 UTC (rev 1955) @@ -281,8 +281,7 @@ rb_objc_block_call(VALUE obj, SEL sel, void *cache, int argc, VALUE *argv, VALUE (*bl_proc) (ANYARGS), VALUE data2) { - NODE *node = NEW_IFUNC(bl_proc, data2); - rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, NULL, NULL, 0, 0); + rb_vm_block_t *b = rb_vm_create_block((IMP)bl_proc, obj, data2); if (cache == NULL) { cache = rb_vm_get_call_cache(sel); }
participants (1)
-
source_changes@macosforge.org