Revision: 1508 http://trac.macosforge.org/projects/ruby/changeset/1508 Author: vincent.isambart@gmail.com Date: 2009-05-01 20:49:04 -0700 (Fri, 01 May 2009) Log Message: ----------- First version of code that save local variables in the heap if they can be used later. It's far from being finished, but it's still a good start. Modified Paths: -------------- MacRuby/branches/experimental/gc.c MacRuby/branches/experimental/proc.c MacRuby/branches/experimental/roxor.cpp MacRuby/branches/experimental/roxor.h MacRuby/branches/experimental/vm_eval.c Modified: MacRuby/branches/experimental/gc.c =================================================================== --- MacRuby/branches/experimental/gc.c 2009-04-30 23:06:00 UTC (rev 1507) +++ MacRuby/branches/experimental/gc.c 2009-05-02 03:49:04 UTC (rev 1508) @@ -239,6 +239,19 @@ VALUE rb_mGC; void +rb_gc_assign_weak_ref(const void *value, void *const*location) +{ + auto_assign_weak_reference(__auto_zone, value, location, NULL); +} + +void* +rb_gc_read_weak_ref(void **referrer) +{ + return auto_read_weak_reference(__auto_zone, referrer); +} + + +void rb_objc_wb(void *dst, void *newval) { if (!SPECIAL_CONST_P(newval)) { Modified: MacRuby/branches/experimental/proc.c =================================================================== --- MacRuby/branches/experimental/proc.c 2009-04-30 23:06:00 UTC (rev 1507) +++ MacRuby/branches/experimental/proc.c 2009-05-02 03:49:04 UTC (rev 1508) @@ -34,12 +34,28 @@ return obj; } +void rb_gc_assign_weak_ref(const void *value, void *const*location); + VALUE rb_proc_alloc_with_block(VALUE klass, rb_vm_block_t *proc) { VALUE obj; obj = Data_Wrap_Struct(klass, NULL, NULL, proc); - proc->flags |= VM_BLOCK_PROC; + if (!(proc->flags & VM_BLOCK_PROC)) { + proc->flags |= VM_BLOCK_PROC; + if (proc->parent_lvar_uses != NULL) { + rb_vm_lvar_uses_t** parent_lvar_uses = proc->parent_lvar_uses; + if ((*parent_lvar_uses == NULL) || ((*parent_lvar_uses)->uses_count == VM_LVAR_USES_SIZE)) { + rb_vm_lvar_uses_t* new_uses = malloc(sizeof(rb_vm_lvar_uses_t)); + new_uses->next = *parent_lvar_uses; + new_uses->uses_count = 0; + *parent_lvar_uses = new_uses; + } + int current_index = (*parent_lvar_uses)->uses_count; + rb_gc_assign_weak_ref(proc, &(*parent_lvar_uses)->uses[current_index]); + ++(*parent_lvar_uses)->uses_count; + } + } return obj; } Modified: MacRuby/branches/experimental/roxor.cpp =================================================================== --- MacRuby/branches/experimental/roxor.cpp 2009-04-30 23:06:00 UTC (rev 1507) +++ MacRuby/branches/experimental/roxor.cpp 2009-05-02 03:49:04 UTC (rev 1508) @@ -231,6 +231,7 @@ ID self_id; Value *current_self; bool current_block; + Value *current_lvar_uses; BasicBlock *begin_bb; BasicBlock *rescue_bb; BasicBlock *ensure_bb; @@ -279,6 +280,7 @@ Function *newRangeFunc; Function *newRegexpFunc; Function *strInternFunc; + Function *keepVarsFunc; Function *masgnGetElemBeforeSplatFunc; Function *masgnGetElemAfterSplatFunc; Function *masgnGetSplatFunc; @@ -324,6 +326,13 @@ : new IntToPtrInst(ptrint, PtrTy, ""); } + Instruction *compile_const_pointer_to_pointer(void *ptr, bool insert_to_bb=true) { + Value *ptrint = ConstantInt::get(IntTy, (long)ptr); + return insert_to_bb + ? new IntToPtrInst(ptrint, PtrPtrTy, "", bb) + : new IntToPtrInst(ptrint, PtrPtrTy, ""); + } + Value *compile_protected_call(Function *func, std::vector<Value *> ¶ms); void compile_dispatch_arguments(NODE *args, std::vector<Value *> &arguments, int *pargc); Function::ArgumentListType::iterator @@ -660,6 +669,7 @@ current_instance_method = false; self_id = rb_intern("self"); current_self = NULL; + current_lvar_uses = NULL; current_block = false; current_block_node = NULL; current_block_func = NULL; @@ -706,6 +716,7 @@ newRangeFunc = NULL; newRegexpFunc = NULL; strInternFunc = NULL; + keepVarsFunc = NULL; masgnGetElemBeforeSplatFunc = NULL; masgnGetElemAfterSplatFunc = NULL; masgnGetSplatFunc = NULL; @@ -1226,11 +1237,13 @@ if (prepareBlockFunc == NULL) { // void *rb_vm_prepare_block(Function *func, NODE *node, VALUE self, + // rb_vm_lvar_uses_t **parent_lvar_uses, // int dvars_size, ...); std::vector<const Type *> types; types.push_back(PtrTy); types.push_back(PtrTy); types.push_back(RubyObjTy); + types.push_back(PtrPtrTy); types.push_back(Type::Int32Ty); FunctionType *ft = FunctionType::get(PtrTy, types, true); prepareBlockFunc = cast<Function> @@ -1241,6 +1254,12 @@ params.push_back(compile_const_pointer(current_block_func)); params.push_back(compile_const_pointer(current_block_node)); params.push_back(current_self); + if (current_lvar_uses == NULL) { + params.push_back(compile_const_pointer_to_pointer(NULL)); + } + else { + params.push_back(current_lvar_uses); + } // Dvars. params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size())); @@ -2984,7 +3003,15 @@ dvars_arg->setName("dvars"); } - if (node->nd_tbl != NULL) { + Value *old_current_lvar_uses = current_lvar_uses; + + if (node->nd_tbl == NULL) { + current_lvar_uses = NULL; + } + else { + current_lvar_uses = new AllocaInst(PtrTy, "", bb); + new StoreInst(compile_const_pointer(NULL), current_lvar_uses, bb); + int i, args_count = (int)node->nd_tbl[0]; assert(args_count == nargs || args_count == nargs + 1 /* optional block */ @@ -3087,6 +3114,39 @@ if (val == NULL) { val = nilVal; } + + // current_lvar_uses has 2 uses or more if it is really used + // (there is always a StoreInst in which we assign it NULL) + if (current_lvar_uses != NULL && current_lvar_uses->hasNUsesOrMore(2)) { + // TODO: only call the function is current_use is not NULL + if (keepVarsFunc == NULL) { + // void rb_vm_keep_vars(rb_vm_lvar_uses_t *uses, int lvars_size, ...); + std::vector<const Type *> types; + types.push_back(PtrTy); + types.push_back(Type::Int32Ty); + FunctionType *ft = FunctionType::get(Type::VoidTy, types, true); + keepVarsFunc = cast<Function> + (module->getOrInsertFunction("rb_vm_keep_vars", ft)); + } + + std::vector<Value *> params; + + params.push_back(new LoadInst(current_lvar_uses, "", bb)); + + params.push_back(ConstantInt::get(Type::Int32Ty, (int)lvars.size())); + for (std::map<ID, Value *>::iterator iter = lvars.begin(); + iter != lvars.end(); ++iter) { + ID name = iter->first; + Value *slot = iter->second; + if (std::find(dvars.begin(), dvars.end(), name) == dvars.end()) { + params.push_back(ConstantInt::get(IntTy, (long)name)); + params.push_back(slot); + } + } + + CallInst::Create(keepVarsFunc, params.begin(), params.end(), "", bb); + } + ReturnInst::Create(val, bb); bb = old_bb; @@ -3094,6 +3154,7 @@ lvars = old_lvars; current_self = old_self; rescue_bb = old_rescue_bb; + current_lvar_uses = old_current_lvar_uses; return cast<Value>(f); } @@ -7681,7 +7742,7 @@ extern "C" rb_vm_block_t * -rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, +rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, rb_vm_lvar_uses_t **parent_lvar_uses, int dvars_size, ...) { NODE *cache_key; @@ -7716,6 +7777,7 @@ } b->flags = 0; b->dvars_size = dvars_size; + b->parent_lvar_uses = NULL; rb_objc_retain(b); GET_VM()->blocks[cache_key] = b; @@ -7728,6 +7790,7 @@ b->self = self; b->node = node; + b->parent_lvar_uses = parent_lvar_uses; va_list ar; va_start(ar, dvars_size); @@ -7757,7 +7820,72 @@ } extern "C" +void* +rb_gc_read_weak_ref(void **referrer); + +struct rb_vm_kept_local { + ID name; + VALUE *stack_address; + VALUE *new_address; +}; + +extern "C" void +rb_vm_keep_vars(rb_vm_lvar_uses_t *uses, int lvars_size, ...) +{ + rb_vm_lvar_uses_t *current = uses; + int use_index; + + while (current != NULL) { + for (use_index = 0; use_index < current->uses_count; ++use_index) { + if (rb_gc_read_weak_ref(¤t->uses[use_index]) != NULL) { + goto use_found; + } + } + + void *old_current = current; + current = current->next; + free(old_current); + } + // no use still alive so nothing to do + return; + +use_found: + rb_vm_kept_local *locals = (rb_vm_kept_local *)alloca(sizeof(rb_vm_kept_local)*lvars_size); + + va_list ar; + va_start(ar, lvars_size); + for (int i = 0; i < lvars_size; ++i) { + locals[i].name = va_arg(ar, ID); + locals[i].stack_address = va_arg(ar, VALUE *); + locals[i].new_address = (VALUE *)xmalloc(sizeof(VALUE)); + GC_WB(locals[i].new_address, *locals[i].stack_address); + } + va_end(ar); + + while (current != NULL) { + for (; use_index < current->uses_count; ++use_index) { + rb_vm_block_t *block = (rb_vm_block_t *)rb_gc_read_weak_ref(¤t->uses[use_index]); + if (block != NULL) { + for (int dvar_index=0; dvar_index<block->dvars_size; ++dvar_index) { + for (int lvar_index=0; lvar_index<lvars_size; ++lvar_index) { + if (block->dvars[dvar_index] == locals[lvar_index].stack_address) { + GC_WB(&block->dvars[dvar_index], locals[lvar_index].new_address); + break; + } + } + } + } + } + void *old_current = current; + current = current->next; + use_index = 0; + free(old_current); + } +} + +extern "C" +void rb_vm_push_binding(VALUE self, int lvars_size, ...) { rb_vm_binding_t *b = (rb_vm_binding_t *)xmalloc(sizeof(rb_vm_binding_t)); Modified: MacRuby/branches/experimental/roxor.h =================================================================== --- MacRuby/branches/experimental/roxor.h 2009-04-30 23:06:00 UTC (rev 1507) +++ MacRuby/branches/experimental/roxor.h 2009-05-02 03:49:04 UTC (rev 1508) @@ -19,6 +19,13 @@ }; typedef struct rb_vm_local rb_vm_local_t; +#define VM_LVAR_USES_SIZE 128 +typedef struct rb_vm_lvar_uses { + int uses_count; + void *uses[VM_LVAR_USES_SIZE]; + struct rb_vm_lvar_uses *next; +} rb_vm_lvar_uses_t; + #define VM_BLOCK_PROC 0x0001 // block is a Proc object #define VM_BLOCK_LAMBDA 0x0002 // block is a lambda #define VM_BLOCK_ACTIVE 0x0004 // block is active (being executed) @@ -30,6 +37,7 @@ IMP imp; int flags; rb_vm_local_t *locals; + rb_vm_lvar_uses_t **parent_lvar_uses; int dvars_size; VALUE *dvars[1]; } rb_vm_block_t; @@ -139,7 +147,8 @@ return (rb_vm_block_t *)DATA_PTR(proc); } -rb_vm_block_t *rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, int dvars_size, ...); +rb_vm_block_t *rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self, + rb_vm_lvar_uses_t **parent_lvar_uses, int dvars_size, ...); rb_vm_block_t *rb_vm_current_block(void); bool rb_vm_block_saved(void); void rb_vm_change_current_block(rb_vm_block_t *block); Modified: MacRuby/branches/experimental/vm_eval.c =================================================================== --- MacRuby/branches/experimental/vm_eval.c 2009-04-30 23:06:00 UTC (rev 1507) +++ MacRuby/branches/experimental/vm_eval.c 2009-05-02 03:49:04 UTC (rev 1508) @@ -277,7 +277,7 @@ 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, 0, 0); + rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, NULL, 0, 0); rb_vm_change_current_block(b); if (cache == NULL) { cache = rb_vm_get_call_cache(sel);
participants (1)
-
source_changes@macosforge.org