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

source_changes at macosforge.org source_changes at macosforge.org
Thu Jul 9 18:29:16 PDT 2009


Revision: 2008
          http://trac.macosforge.org/projects/ruby/changeset/2008
Author:   lsansonetti at apple.com
Date:     2009-07-09 18:29:15 -0700 (Thu, 09 Jul 2009)
Log Message:
-----------
a new implementation for return-from-block which uses an exception instead of SjLj

Modified Paths:
--------------
    MacRuby/branches/experimental/compiler.cpp
    MacRuby/branches/experimental/compiler.h
    MacRuby/branches/experimental/vm.cpp
    MacRuby/branches/experimental/vm.h

Modified: MacRuby/branches/experimental/compiler.cpp
===================================================================
--- MacRuby/branches/experimental/compiler.cpp	2009-07-09 04:15:23 UTC (rev 2007)
+++ MacRuby/branches/experimental/compiler.cpp	2009-07-10 01:29:15 UTC (rev 2008)
@@ -58,7 +58,7 @@
     current_loop_end_bb = NULL;
     current_loop_exit_val = NULL;
     current_rescue = false;
-    return_from_block_jmpbuf = NULL;
+    return_from_block = false;
 
     dispatcherFunc = NULL;
     fastEqqFunc = NULL;
@@ -113,6 +113,8 @@
     popExceptionFunc = NULL;
     getSpecialFunc = NULL;
     breakFunc = NULL;
+    returnFromBlockFunc = NULL;
+    returnFromBlockValueFunc = NULL;
     longjmpFunc = NULL;
     setjmpFunc = NULL;
     popBrokenValue = NULL;
@@ -1439,10 +1441,52 @@
     }
     std::vector<Value *> params;
     params.push_back(val);
-    CallInst::Create(breakFunc, params.begin(),
-	    params.end(), "", bb);
+    CallInst::Create(breakFunc, params.begin(), params.end(), "", bb);
 }
 
+void
+RoxorCompiler::compile_return_from_block(Value *val)
+{
+    if (returnFromBlockFunc == NULL) {
+	// void rb_vm_return_from_block(VALUE val);
+	returnFromBlockFunc = cast<Function>(
+		module->getOrInsertFunction("rb_vm_return_from_block", 
+		    Type::VoidTy, RubyObjTy, NULL));
+    }
+    std::vector<Value *> params;
+    params.push_back(val);
+    CallInst::Create(returnFromBlockFunc, params.begin(), params.end(), "", bb);
+}
+
+void
+RoxorCompiler::compile_return_from_block_handler(void)
+{
+    compile_landing_pad_header();
+
+    if (returnFromBlockValueFunc == NULL) {
+	returnFromBlockValueFunc = cast<Function>(
+		module->getOrInsertFunction(
+		    "rb_vm_pop_return_from_block_value", 
+		    RubyObjTy, NULL));
+    }
+
+    Value *val = CallInst::Create(returnFromBlockValueFunc, "", bb);
+
+    Function *f = bb->getParent();
+    BasicBlock *ret_bb = BasicBlock::Create("ret", f);
+    BasicBlock *rethrow_bb  = BasicBlock::Create("rethrow", f);
+    Value *need_ret = new ICmpInst(ICmpInst::ICMP_NE, val,
+	    ConstantInt::get(RubyObjTy, Qundef), "", bb);
+    BranchInst::Create(ret_bb, rethrow_bb, need_ret, bb);
+
+    bb = ret_bb;
+    compile_landing_pad_footer(false);
+    ReturnInst::Create(val, bb);	
+
+    bb = rethrow_bb;
+    compile_rethrow_exception();
+}
+
 Value *
 RoxorCompiler::compile_jump(NODE *node)
 {
@@ -1514,24 +1558,8 @@
 		compile_pop_exception();
 	    }
 	    if (within_block) {
-		compile_break_val(val);
-		// Return-from-block is implemented using a setjmp() call.
-		if (longjmpFunc == NULL) {
-		    // void longjmp(jmp_buf, int);
-		    longjmpFunc = cast<Function>(
-			    module->getOrInsertFunction("longjmp", 
-				Type::VoidTy, PtrTy, Type::Int32Ty, NULL));
-		}
-		std::vector<Value *> params;
-		if (return_from_block_jmpbuf == NULL) {
-		    return_from_block_jmpbuf = 
-			(jmp_buf *)malloc(sizeof(jmp_buf));
-		}
-		params.push_back(compile_const_pointer(
-			    return_from_block_jmpbuf));
-		params.push_back(ConstantInt::get(Type::Int32Ty, 1));
-		CallInst::Create(longjmpFunc, params.begin(), params.end(), "",
-			bb);
+		return_from_block = true;
+		compile_return_from_block(val);
 		ReturnInst::Create(val, bb);
 	    }
 	    else {
@@ -1624,9 +1652,11 @@
 }
 
 void
-RoxorCompiler::compile_landing_pad_footer(void)
+RoxorCompiler::compile_landing_pad_footer(bool pop_exception)
 {
-    compile_pop_exception();
+    if (pop_exception) {
+	compile_pop_exception();
+    }
 
     Function *endCatchFunc = NULL;
     if (endCatchFunc == NULL) {
@@ -4301,55 +4331,25 @@
 		NODE *old_current_block_node = current_block_node;
 		ID old_current_mid = current_mid;
 		bool old_current_block = current_block;
-		jmp_buf *old_return_from_block_jmpbuf =
-		    return_from_block_jmpbuf;
+		bool old_return_from_block = return_from_block;
+		BasicBlock *old_rescue_bb = rescue_bb;
 
 		current_mid = 0;
 		current_block = true;
-		return_from_block_jmpbuf = NULL;
 
 		assert(node->nd_body != NULL);
 		Value *block = compile_node(node->nd_body);	
 		assert(Function::classof(block));
 
-		if (return_from_block_jmpbuf != NULL) {
-		    // The block we just compiled contains one (or more)
-		    // return expressions and provided us a longjmp buffer.
-		    // Let's compile a call to setjmp() and make sure to
-		    // return if its return value is non-zero.
-		    if (setjmpFunc == NULL) {
-			// int setjmp(jmp_buf);
-			setjmpFunc = cast<Function>(
-				module->getOrInsertFunction("setjmp", 
-				    Type::Int32Ty, PtrTy, NULL));
-		    }
-		    std::vector<Value *> params;
-		    params.push_back(compile_const_pointer(
-				return_from_block_jmpbuf));
-		    Value *retval = CallInst::Create(setjmpFunc,
-			    params.begin(), params.end(), "", bb);
-
+		BasicBlock *return_from_block_bb = NULL;
+		if (!old_return_from_block && return_from_block) {
+		    // The block we just compiled contains one or more
+		    // return expressions! We need to enclose the dispatcher
+		    // call inside an exception handler, since return-from
+		    // -block is implemented using a C++ exception.
 		    Function *f = bb->getParent();
-		    BasicBlock *ret_bb = BasicBlock::Create("ret", f);
-		    BasicBlock *no_ret_bb  = BasicBlock::Create("no_ret", f);
-		    Value *need_ret = new ICmpInst(ICmpInst::ICMP_NE, 
-			    retval, ConstantInt::get(Type::Int32Ty, 0), 
-			    "", bb);
-		    BranchInst::Create(ret_bb, no_ret_bb, need_ret, bb);
-		
-		    bb = ret_bb;
-		    if (popBrokenValue == NULL) {
-			// VALUE rb_vm_pop_broken_value(void);
-			popBrokenValue = cast<Function>(
-				module->getOrInsertFunction(
-				    "rb_vm_pop_broken_value", 
-				    RubyObjTy, NULL));
-		    }
-		    params.clear();
-		    Value *val = compile_protected_call(popBrokenValue, params);
-		    ReturnInst::Create(val, bb);	
-
-		    bb = no_ret_bb;
+		    rescue_bb = return_from_block_bb = BasicBlock::Create(
+			    "return-from-block", f);
 		}
 
 		current_loop_begin_bb = old_current_loop_begin_bb;
@@ -4381,9 +4381,17 @@
 		    caller = compile_dispatch_call(params);
 		}
 
+		if (return_from_block_bb) {
+		    BasicBlock *old_bb = bb;
+		    bb = return_from_block_bb;
+		    compile_return_from_block_handler();	
+		    rescue_bb = old_rescue_bb;
+		    bb = old_bb;
+		}
+
+		return_from_block = old_return_from_block;
 		current_block_func = old_current_block_func;
 		current_block_node = old_current_block_node;
-		return_from_block_jmpbuf = old_return_from_block_jmpbuf;
 		dvars = old_dvars;
 
 		return caller;

Modified: MacRuby/branches/experimental/compiler.h
===================================================================
--- MacRuby/branches/experimental/compiler.h	2009-07-09 04:15:23 UTC (rev 2007)
+++ MacRuby/branches/experimental/compiler.h	2009-07-10 01:29:15 UTC (rev 2008)
@@ -86,13 +86,13 @@
 	bool current_rescue;
 	NODE *current_block_node;
 	Function *current_block_func;
-	jmp_buf *return_from_block_jmpbuf;
 	GlobalVariable *current_opened_class;
 	bool current_module;
 	BasicBlock *current_loop_begin_bb;
 	BasicBlock *current_loop_body_bb;
 	BasicBlock *current_loop_end_bb;
 	Value *current_loop_exit_val;
+	bool return_from_block;
 
 	Function *dispatcherFunc;
 	Function *fastEqqFunc;
@@ -147,6 +147,8 @@
 	Function *popExceptionFunc;
 	Function *getSpecialFunc;
 	Function *breakFunc;
+	Function *returnFromBlockFunc;
+	Function *returnFromBlockValueFunc;
 	Function *longjmpFunc;
 	Function *setjmpFunc;
 	Function *popBrokenValue;
@@ -227,6 +229,8 @@
 	Value *compile_dstr(NODE *node);
 	Value *compile_dvar_slot(ID name);
 	void compile_break_val(Value *val);
+	void compile_return_from_block(Value *val);
+	void compile_return_from_block_handler(void);
 	Value *compile_jump(NODE *node);
 	virtual Value *compile_mcache(SEL sel, bool super);
 	virtual Value *compile_ccache(ID id);
@@ -245,7 +249,7 @@
 	virtual Value *compile_global_entry(NODE *node);
 
 	void compile_landing_pad_header(void);
-	void compile_landing_pad_footer(void);
+	void compile_landing_pad_footer(bool pop_exception=true);
 	void compile_rethrow_exception(void);
 	void compile_pop_exception(void);
 	Value *compile_lvar_slot(ID name);

Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp	2009-07-09 04:15:23 UTC (rev 2007)
+++ MacRuby/branches/experimental/vm.cpp	2009-07-10 01:29:15 UTC (rev 2008)
@@ -237,6 +237,7 @@
     safe_level = 0;
     backref = Qnil;
     broken_with = Qundef;
+    returned_from_block = false;
     last_status = Qnil;
     errinfo = Qnil;
     parse_in_eval = false;
@@ -292,6 +293,7 @@
 
     backref = Qnil;
     broken_with = Qundef;
+    returned_from_block = false;
     last_status = Qnil;
     errinfo = Qnil;
     parse_in_eval = false;
@@ -3833,8 +3835,37 @@
     return val;
 }
 
+static inline void
+rb_vm_rethrow(void)
+{
+    void *exc = __cxa_allocate_exception(0);
+    __cxa_throw(exc, NULL, NULL);
+}
+
 extern "C"
+void
+rb_vm_return_from_block(VALUE val)
+{
+    GET_VM()->set_broken_with(val);
+    GET_VM()->set_returned_from_block(true);
+    rb_vm_rethrow();
+}
+
+extern "C"
 VALUE
+rb_vm_pop_return_from_block_value(void)
+{
+    if (GET_VM()->get_returned_from_block()) {
+	GET_VM()->set_returned_from_block(false);
+	VALUE val = rb_vm_pop_broken_value();
+	assert(val != Qundef);
+	return val;
+    }
+    return Qundef;
+}
+
+extern "C"
+VALUE
 rb_vm_backtrace(int level)
 {
     void *callstack[128];
@@ -3860,14 +3891,6 @@
 }
 
 extern "C"
-void
-rb_vm_rethrow(void)
-{
-    void *exc = __cxa_allocate_exception(0);
-    __cxa_throw(exc, NULL, NULL);
-}
-
-extern "C"
 unsigned char
 rb_vm_is_eh_active(int argc, ...)
 {
@@ -4490,7 +4513,14 @@
 	GC_WB(&t->value, val);
     }
     catch (...) {
-	VALUE exc = rb_vm_current_exception();
+	VALUE exc;
+	if (rb_vm_pop_return_from_block_value() != Qundef) {
+	    exc = rb_exc_new2(rb_eLocalJumpError,
+		    "unexpected return from Thread");
+	}
+	else {
+	    exc = rb_vm_current_exception();
+	}
 	if (exc != Qnil) {
 	    GC_WB(&t->exception, exc);
 	}

Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h	2009-07-09 04:15:23 UTC (rev 2007)
+++ MacRuby/branches/experimental/vm.h	2009-07-10 01:29:15 UTC (rev 2008)
@@ -750,6 +750,7 @@
 	VALUE current_top_object;
 	VALUE backref;
 	VALUE broken_with;
+	bool returned_from_block;
 	VALUE last_status;
 	VALUE errinfo;
 	int safe_level;
@@ -766,6 +767,7 @@
 	ACCESSOR(current_top_object, VALUE);
 	ACCESSOR(backref, VALUE);
 	ACCESSOR(broken_with, VALUE);
+	ACCESSOR(returned_from_block, bool);
 	ACCESSOR(last_status, VALUE);
 	ACCESSOR(errinfo, VALUE);
 	ACCESSOR(safe_level, int);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090709/7dde032b/attachment-0001.html>


More information about the macruby-changes mailing list