[macruby-changes] [3461] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Feb 9 14:39:30 PST 2010


Revision: 3461
          http://trac.macosforge.org/projects/ruby/changeset/3461
Author:   lsansonetti at apple.com
Date:     2010-02-09 14:39:29 -0800 (Tue, 09 Feb 2010)
Log Message:
-----------
when doing an assignment from thread X to thread Y's stack, defeat the thread-local collector by making X take ownership of the object

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/dispatcher.cpp
    MacRuby/trunk/vm.cpp
    MacRuby/trunk/vm.h

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-02-09 02:06:07 UTC (rev 3460)
+++ MacRuby/trunk/compiler.cpp	2010-02-09 22:39:29 UTC (rev 3461)
@@ -148,6 +148,7 @@
     debugTrapFunc = NULL;
     getFFStateFunc = NULL;
     setFFStateFunc = NULL;
+    takeOwnershipFunc = NULL;
 
     VoidTy = Type::getVoidTy(context);
     Int1Ty = Type::getInt1Ty(context);
@@ -3454,8 +3455,52 @@
 		assert(node->nd_value != NULL);
 
 		Value *new_val = compile_node(node->nd_value);
+
+		const int type = nd_type(node);
+		if ((type == NODE_DASGN || type == NODE_DASGN_CURR)
+			&& running_block != NULL) {
+		    // Dynamic variables assignments inside a block are a
+		    // little bit complicated: if we are creating new objects
+		    // we do need to defeat the thread-local collector by
+		    // taking ownership of the objects, otherwise the TLC might
+		    // prematurely collect them. This is because the assignment
+		    // is done into another thread's stack, which is not
+		    // honored by the TLC.
+		    Value *flag = new BitCastInst(running_block, Int32PtrTy,
+			    "", bb);
+		    flag = new LoadInst(flag, "", bb);
+		    Value *flagv = ConstantInt::get(Int32Ty, VM_BLOCK_THREAD);
+		    flag = BinaryOperator::CreateAnd(flag, flagv, "", bb);
+		    Value *is_thread = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
+			    flag, flagv);
+
+		    Function *f = bb->getParent();
+		    BasicBlock *is_thread_bb =
+			BasicBlock::Create(context, "", f);
+		    BasicBlock *merge_bb =
+			BasicBlock::Create(context, "", f);
+
+		    BranchInst::Create(is_thread_bb, merge_bb,
+			    is_thread, bb);
+
+		    bb = is_thread_bb;
+		    if (takeOwnershipFunc == NULL) {
+			takeOwnershipFunc =
+			    cast<Function>(module->getOrInsertFunction(
+				"rb_vm_take_ownership",
+				VoidTy, RubyObjTy, NULL));
+		    }
+
+		    std::vector<Value *> params;
+		    params.push_back(new_val);
+		    CallInst::Create(takeOwnershipFunc, params.begin(),
+			    params.end(), "", bb);
+		    BranchInst::Create(merge_bb, bb);
+
+		    bb = merge_bb;
+		}
+
 		new StoreInst(new_val, compile_lvar_slot(node->nd_vid), bb);
-
 		return new_val;
 	    }
 	    break;

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-02-09 02:06:07 UTC (rev 3460)
+++ MacRuby/trunk/compiler.h	2010-02-09 22:39:29 UTC (rev 3461)
@@ -197,9 +197,9 @@
 	Function *setCurrentClassFunc;
 	Function *getCacheFunc;
 	Function *debugTrapFunc;
-	// flip-flop
 	Function *getFFStateFunc;
 	Function *setFFStateFunc;
+	Function *takeOwnershipFunc;
 
 	Constant *zeroVal;
 	Constant *oneVal;

Modified: MacRuby/trunk/dispatcher.cpp
===================================================================
--- MacRuby/trunk/dispatcher.cpp	2010-02-09 02:06:07 UTC (rev 3460)
+++ MacRuby/trunk/dispatcher.cpp	2010-02-09 22:39:29 UTC (rev 3461)
@@ -1573,6 +1573,16 @@
 
     vm->pop_current_block();
 
+    rb_vm_block_t *top_b = vm->current_block();
+    if (top_b == NULL) {
+	if (vm != RoxorVM::main) {
+	    top_b = GetThreadPtr(vm->get_thread())->body;
+	}
+    }
+    if (top_b != NULL && (top_b->flags & VM_BLOCK_THREAD)) {
+	b->flags |= VM_BLOCK_THREAD;
+    }
+
     struct Finally {
 	RoxorVM *vm;
 	rb_vm_block_t *b;
@@ -1582,6 +1592,7 @@
 	}
 	~Finally() {
 	    vm->add_current_block(b);
+	    b->flags &= ~VM_BLOCK_THREAD;
 	}
     } finalizer(vm, b);
 
@@ -1696,6 +1707,10 @@
 	aot_block = true;
     }
 
+    if (parent_block != NULL && (parent_block->flags & VM_BLOCK_THREAD)) {
+	flags |= VM_BLOCK_THREAD;
+    }
+
     if (!cached) {
 	if ((flags & VM_BLOCK_IFUNC) == VM_BLOCK_IFUNC) {
 	    b->imp = (IMP)function;

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-02-09 02:06:07 UTC (rev 3460)
+++ MacRuby/trunk/vm.cpp	2010-02-09 22:39:29 UTC (rev 3461)
@@ -4598,6 +4598,18 @@
 
 extern "C"
 void
+rb_vm_take_ownership(VALUE obj)
+{
+    // This function allows the given object's ownership to be transfered to
+    // the current thread. It is used when objects are allocated from a
+    // thread but assigned into another thread's stack, which is prohibited by
+    // the thread-local collector.
+    GC_RETAIN(obj);
+    GC_RELEASE(obj);
+}
+
+extern "C"
+void
 rb_vm_thread_pre_init(rb_vm_thread_t *t, rb_vm_block_t *body, int argc,
 	const VALUE *argv, void *vm)
 {
@@ -4607,12 +4619,13 @@
 	GC_WB(&t->body, body);
 	rb_vm_block_make_detachable_proc(body);
 
-	// Remove the thread-local bit of all dynamic variables.
+	// Take ownership of all dynamic variables, mark the block as
+	// being run from a thread.
 	for (int i = 0; i < body->dvars_size; i++) {
 	    VALUE *dvar = body->dvars[i];
-	    GC_RETAIN(*dvar);
-	    GC_RELEASE(*dvar);
+	    rb_vm_take_ownership(*dvar);
 	}
+	body->flags |= VM_BLOCK_THREAD;
     }
     else {
 	t->body = NULL;

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-02-09 02:06:07 UTC (rev 3460)
+++ MacRuby/trunk/vm.h	2010-02-09 22:39:29 UTC (rev 3461)
@@ -26,24 +26,26 @@
     struct rb_vm_local *next;
 } rb_vm_local_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)
-#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_PROC	(1<<0)	// block is a Proc object
+#define VM_BLOCK_LAMBDA (1<<1)	// block is a lambda
+#define VM_BLOCK_ACTIVE (1<<2)	// block is active (being executed)
+#define VM_BLOCK_METHOD (1<<3)	// block is created from Method
+#define VM_BLOCK_IFUNC  (1<<4)  // block is created from rb_vm_create_block()
+#define VM_BLOCK_EMPTY  (1<<5)	// block has an empty body
+#define VM_BLOCK_THREAD (1<<6)	// block is being executed as a Thread
+#define VM_BLOCK_AOT	(1<<10) // block is created by the AOT compiler
+				// (temporary)
 
-#define VM_BLOCK_AOT	0x1000  // block is created by the AOT compiler (temporary)
-
 typedef struct rb_vm_block {
-    VALUE proc; // a reference to a Proc object, or nil
+    int flags; 	// IMPORTANT: this field should always be at the beginning.
+		// Look at how rb_vm_take_ownership() is called in compiler.cpp.
+    VALUE proc; // a reference to a Proc object, or nil.
     VALUE self;
     VALUE klass;
     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;
     rb_vm_local_t *locals;
     struct rb_vm_var_uses **parent_var_uses;
     struct rb_vm_block *parent_block;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100209/c868ccf1/attachment.html>


More information about the macruby-changes mailing list