[macruby-changes] [1508] MacRuby/branches/experimental

source_changes at macosforge.org source_changes at macosforge.org
Fri May 1 20:49:05 PDT 2009


Revision: 1508
          http://trac.macosforge.org/projects/ruby/changeset/1508
Author:   vincent.isambart at 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 *> &params);
 	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(&current->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(&current->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);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090501/bc4523f0/attachment-0001.html>


More information about the macruby-changes mailing list