[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