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

source_changes at macosforge.org source_changes at macosforge.org
Tue May 5 19:26:33 PDT 2009


Revision: 1538
          http://trac.macosforge.org/projects/ruby/changeset/1538
Author:   vincent.isambart at gmail.com
Date:     2009-05-05 19:26:32 -0700 (Tue, 05 May 2009)
Log Message:
-----------
finished the save of local variables, this time also saving variables used in blocks that are in other blocks

Modified Paths:
--------------
    MacRuby/branches/experimental/proc.c
    MacRuby/branches/experimental/roxor.cpp
    MacRuby/branches/experimental/roxor.h
    MacRuby/branches/experimental/test_vm/block.rb
    MacRuby/branches/experimental/vm_eval.c

Modified: MacRuby/branches/experimental/proc.c
===================================================================
--- MacRuby/branches/experimental/proc.c	2009-05-05 22:50:52 UTC (rev 1537)
+++ MacRuby/branches/experimental/proc.c	2009-05-06 02:26:32 UTC (rev 1538)
@@ -41,9 +41,7 @@
     obj = Data_Wrap_Struct(klass, NULL, NULL, proc);
     if (!(proc->flags & VM_BLOCK_PROC)) {
 	proc->flags |= VM_BLOCK_PROC;
-	if (proc->parent_var_uses != NULL) {
-	    rb_vm_add_var_use(proc->parent_var_uses, proc);
-	}
+	rb_vm_add_var_use(proc);
     }
     return obj;
 }

Modified: MacRuby/branches/experimental/roxor.cpp
===================================================================
--- MacRuby/branches/experimental/roxor.cpp	2009-05-05 22:50:52 UTC (rev 1537)
+++ MacRuby/branches/experimental/roxor.cpp	2009-05-06 02:26:32 UTC (rev 1538)
@@ -231,6 +231,7 @@
 	Value *current_self;
 	bool current_block;
 	Value *current_var_uses;
+	Value *running_block;
 	BasicBlock *begin_bb;
 	BasicBlock *rescue_bb;
 	BasicBlock *ensure_bb;
@@ -678,6 +679,7 @@
     self_id = rb_intern("self");
     current_self = NULL;
     current_var_uses = NULL;
+    running_block = NULL;
     current_block = false;
     current_block_node = NULL;
     current_block_func = NULL;
@@ -1250,12 +1252,14 @@
     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, ...);
 	std::vector<const Type *> types;
 	types.push_back(PtrTy);
 	types.push_back(PtrTy);
 	types.push_back(RubyObjTy);
 	types.push_back(PtrPtrTy);
+	types.push_back(PtrTy);
 	types.push_back(Type::Int32Ty);
 	FunctionType *ft = FunctionType::get(PtrTy, types, true);
 	prepareBlockFunc = cast<Function>
@@ -1273,6 +1277,12 @@
     else {
 	params.push_back(current_var_uses);
     }
+    if (running_block == NULL) {
+	params.push_back(compile_const_pointer(NULL));
+    }
+    else {
+	params.push_back(running_block);
+    }
 
     // Dvars.
     params.push_back(ConstantInt::get(Type::Int32Ty, (int)dvars.size()));
@@ -3021,6 +3031,7 @@
 		types.push_back(PtrTy);		// sel
 		if (has_dvars) {
 		    types.push_back(RubyObjPtrPtrTy); // dvars array
+		    types.push_back(PtrTy); // rb_vm_block_t of the currently running block
 		}
 		for (int i = 0; i < nargs; ++i) {
 		    types.push_back(RubyObjTy);
@@ -3048,20 +3059,22 @@
 		Value *sel = arg++;
 		sel->setName("sel");
 
+		Value *old_running_block = running_block;
 		Value *old_current_var_uses = current_var_uses;
+		current_var_uses = NULL;
 
 		if (has_dvars) {
 		    Value *dvars_arg = arg++;
 		    dvars_arg->setName("dvars");
+		    running_block = arg++;
+		    running_block->setName("running_block");
 		}
-
-		if (node->nd_tbl == NULL) {
-		    current_var_uses = NULL;
+		else {
+		    running_block = NULL;
 		}
-		else {
-		    current_var_uses = new AllocaInst(PtrTy, "", bb);
-		    new StoreInst(compile_const_pointer(NULL), current_var_uses, bb);
 
+		if (node->nd_tbl != NULL) {
+		    bool has_vars_to_save = false;
 		    int i, args_count = (int)node->nd_tbl[0];
 		    assert(args_count == nargs
 			    || args_count == nargs + 1 /* optional block */
@@ -3090,6 +3103,7 @@
 			Value *slot = new AllocaInst(RubyObjTy, "", bb);
 			new StoreInst(val, slot, bb);
 			lvars[id] = slot;
+			has_vars_to_save = true;
 		    }
 
 		    // local vars must be created before the optional arguments
@@ -3107,9 +3121,15 @@
 			    Value *store = new AllocaInst(RubyObjTy, "", bb);
 			    new StoreInst(nilVal, store, bb);
 			    lvars[id] = store;
+			    has_vars_to_save = true;
 			}
 		    }
 
+		    if (has_vars_to_save) {
+			current_var_uses = new AllocaInst(PtrTy, "", bb);
+			new StoreInst(compile_const_pointer(NULL), current_var_uses, bb);
+		    }
+
 		    NODE *args_node = node->nd_args;
 		    if (args_node != NULL) {
 			// compile multiple assignment arguments (def f((a, b, v)))
@@ -3141,7 +3161,7 @@
 			if (opt_node != NULL) {
 			    int to_skip = args_node->nd_frml;
 			    if (has_dvars) {
-				to_skip++; // dvars array
+				to_skip += 2; // dvars array and currently running block
 			    }
 			    for (i = 0; i < to_skip; i++) {
 				++iter; // skip dvars and args required on the left-side
@@ -3219,6 +3239,7 @@
 		current_self = old_self;
 		rescue_bb = old_rescue_bb;
 		current_var_uses = old_current_var_uses;
+		running_block = old_running_block;
 
 		return cast<Value>(f);
 	    }
@@ -7075,7 +7096,7 @@
 
 __attribute__((always_inline))
 static VALUE
-__rb_vm_bcall(VALUE self, VALUE dvars,
+__rb_vm_bcall(VALUE self, VALUE dvars, rb_vm_block_t *b,
 	      IMP pimp, const rb_vm_arity_t &arity, int argc, const VALUE *argv)
 {
     if ((arity.real != argc) || (arity.max == -1)) {
@@ -7128,29 +7149,29 @@
 
     assert(pimp != NULL);
 
-    VALUE (*imp)(VALUE, SEL, VALUE, ...) = (VALUE (*)(VALUE, SEL, VALUE, ...))pimp;
+    VALUE (*imp)(VALUE, SEL, VALUE, rb_vm_block_t *,  ...) = (VALUE (*)(VALUE, SEL, VALUE, rb_vm_block_t *, ...))pimp;
 
     switch (argc) {
 	case 0:
-	    return (*imp)(self, 0, dvars);
+	    return (*imp)(self, 0, dvars, b);
 	case 1:
-	    return (*imp)(self, 0, dvars, argv[0]);
+	    return (*imp)(self, 0, dvars, b, argv[0]);
 	case 2:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1]);		
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1]);
 	case 3:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2]);
 	case 4:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3]);
 	case 5:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3], argv[4]);
 	case 6:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
 	case 7:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
 	case 8:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
 	case 9:
-	    return (*imp)(self, 0, dvars, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
+	    return (*imp)(self, 0, dvars, b, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
     }	
     printf("invalid argc %d\n", argc);
     abort();
@@ -7812,7 +7833,7 @@
     GET_VM()->previous_block = old_b;
 
     if (!GET_VM()->bindings.empty()) {
-	rb_objc_release(GET_VM()->bindings.back());	
+	rb_objc_release(GET_VM()->bindings.back());
 	GET_VM()->bindings.pop_back();
     }
 
@@ -7944,6 +7965,7 @@
 rb_vm_block_t *
 rb_vm_prepare_block(void *llvm_function, NODE *node, VALUE self,
 		    rb_vm_var_uses **parent_var_uses,
+		    rb_vm_block_t *parent_block,
 		    int dvars_size, ...)
 {
     NODE *cache_key;
@@ -7979,6 +8001,7 @@
 	b->flags = 0;
 	b->dvars_size = dvars_size;
 	b->parent_var_uses = NULL;
+	b->parent_block = NULL;
 
 	rb_objc_retain(b);
 	GET_VM()->blocks[cache_key] = b;
@@ -7992,6 +8015,7 @@
     b->self = self;
     b->node = node;
     b->parent_var_uses = parent_var_uses;
+    b->parent_block = parent_block;
 
     va_list ar;
     va_start(ar, dvars_size);
@@ -8037,18 +8061,24 @@
 
 extern "C"
 void
-rb_vm_add_var_use(rb_vm_var_uses **var_uses, rb_vm_block_t *proc)
+rb_vm_add_var_use(rb_vm_block_t *block)
 {
-    assert(var_uses != NULL);
-    if ((*var_uses == NULL) || ((*var_uses)->uses_count == VM_LVAR_USES_SIZE)) {
-	rb_vm_var_uses* new_uses = (rb_vm_var_uses*)malloc(sizeof(rb_vm_var_uses));
-	new_uses->next = *var_uses;
-	new_uses->uses_count = 0;
-	*var_uses = new_uses;
+    for (rb_vm_block_t *block_for_uses = block; block_for_uses != NULL; block_for_uses = block_for_uses->parent_block) {
+	rb_vm_var_uses **var_uses = block_for_uses->parent_var_uses;
+	if (var_uses == NULL) {
+	    continue;
+	}
+	if ((*var_uses == NULL) || ((*var_uses)->uses_count == VM_LVAR_USES_SIZE)) {
+	    rb_vm_var_uses* new_uses = (rb_vm_var_uses*)malloc(sizeof(rb_vm_var_uses));
+	    new_uses->next = *var_uses;
+	    new_uses->uses_count = 0;
+	    *var_uses = new_uses;
+	}
+	int current_index = (*var_uses)->uses_count;
+	rb_gc_assign_weak_ref(block, &(*var_uses)->uses[current_index]);
+	++(*var_uses)->uses_count;
     }
-    int current_index = (*var_uses)->uses_count;
-    rb_gc_assign_weak_ref(proc, &(*var_uses)->uses[current_index]);
-    ++(*var_uses)->uses_count;
+    block->parent_block = NULL; // we should not keep references that won't be used
 }
 
 struct rb_vm_kept_local {
@@ -8095,8 +8125,8 @@
 	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) {
+		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;
@@ -8363,7 +8393,7 @@
 
     assert(!(b->flags & VM_BLOCK_ACTIVE));
     b->flags |= VM_BLOCK_ACTIVE;
-    VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars,
+    VALUE v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b,
 			    b->imp, b->arity, argc, argv);
     b->flags &= ~VM_BLOCK_ACTIVE;
 

Modified: MacRuby/branches/experimental/roxor.h
===================================================================
--- MacRuby/branches/experimental/roxor.h	2009-05-05 22:50:52 UTC (rev 1537)
+++ MacRuby/branches/experimental/roxor.h	2009-05-06 02:26:32 UTC (rev 1538)
@@ -23,7 +23,7 @@
 #define VM_BLOCK_LAMBDA 0x0002	// block is a lambda
 #define VM_BLOCK_ACTIVE 0x0004	// block is active (being executed)
 
-typedef struct {
+typedef struct rb_vm_block {
     VALUE self;
     NODE *node;
     rb_vm_arity_t arity;
@@ -31,6 +31,7 @@
     int flags;
     rb_vm_local_t *locals;
     struct rb_vm_var_uses **parent_var_uses;
+    struct rb_vm_block *parent_block;
     int dvars_size;
     VALUE *dvars[1];
 } rb_vm_block_t;
@@ -140,9 +141,10 @@
    return (rb_vm_block_t *)DATA_PTR(proc);
 }
 
-void rb_vm_add_var_use(struct rb_vm_var_uses **uses, rb_vm_block_t *proc);
+void rb_vm_add_var_use(rb_vm_block_t *proc);
 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_current_block(void);
 bool rb_vm_block_saved(void);

Modified: MacRuby/branches/experimental/test_vm/block.rb
===================================================================
--- MacRuby/branches/experimental/test_vm/block.rb	2009-05-05 22:50:52 UTC (rev 1537)
+++ MacRuby/branches/experimental/test_vm/block.rb	2009-05-06 02:26:32 UTC (rev 1538)
@@ -371,5 +371,21 @@
   p f.call
 }
 
+assert ':ok', %{
+  $a = []
+  
+  def foo(what, &block)
+    $a << block
+  end
+  
+  [:ok].each do |type|
+    foo type do
+      p type
+    end
+  end
+  
+  $a.each do |b| b.call end
+}
+
 # Enumerator 
 assert "[\"f\", \"o\", \"o\"]", "p 'foo'.chars.to_a"

Modified: MacRuby/branches/experimental/vm_eval.c
===================================================================
--- MacRuby/branches/experimental/vm_eval.c	2009-05-05 22:50:52 UTC (rev 1537)
+++ MacRuby/branches/experimental/vm_eval.c	2009-05-06 02:26:32 UTC (rev 1538)
@@ -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, NULL, 0, 0);
+    rb_vm_block_t *b = rb_vm_prepare_block(NULL, node, obj, NULL, 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/20090505/7fa85ea5/attachment-0001.html>


More information about the macruby-changes mailing list