[macruby-changes] [2950] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Nov 3 22:05:33 PST 2009


Revision: 2950
          http://trac.macosforge.org/projects/ruby/changeset/2950
Author:   lsansonetti at apple.com
Date:     2009-11-03 22:05:31 -0800 (Tue, 03 Nov 2009)
Log Message:
-----------
optimized returns from non-ensure-scoped and non-Proc blocks

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

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2009-11-03 07:22:20 UTC (rev 2949)
+++ MacRuby/trunk/compiler.cpp	2009-11-04 06:05:31 UTC (rev 2950)
@@ -124,7 +124,9 @@
     getSpecialFunc = NULL;
     breakFunc = NULL;
     returnFromBlockFunc = NULL;
+    returnedFromBlockFunc = NULL;
     checkReturnFromBlockFunc = NULL;
+    setHasEnsureFunc = NULL;
     longjmpFunc = NULL;
     setjmpFunc = NULL;
     setScopeFunc = NULL;
@@ -357,7 +359,8 @@
 }
 
 void
-RoxorCompiler::compile_dispatch_arguments(NODE *args, std::vector<Value *> &arguments, int *pargc)
+RoxorCompiler::compile_dispatch_arguments(NODE *args,
+	std::vector<Value *> &arguments, int *pargc)
 {
     int argc = 0;
 
@@ -1791,6 +1794,21 @@
 }
 
 Value *
+RoxorCompiler::compile_set_has_ensure(Value *val)
+{
+    if (setHasEnsureFunc == NULL) {
+	setHasEnsureFunc = cast<Function>(
+		module->getOrInsertFunction(
+		    "rb_vm_set_has_ensure", Int8Ty, Int8Ty, NULL));
+    }
+
+    std::vector<Value *> params;
+    params.push_back(val);
+    return CallInst::Create(setHasEnsureFunc, params.begin(), params.end(),
+	    "", bb);
+}
+
+Value *
 RoxorCompiler::compile_class_path(NODE *node, bool *outer)
 {
     if (nd_type(node) == NODE_COLON3) {
@@ -4817,7 +4835,6 @@
 		PHINode *new_ensure_pn = PHINode::Create(RubyObjTy,
 			"ensure.phi", ensure_return_bb);
 		ensure_pn = new_ensure_pn;
-		Value *val;
 
 		ensure_bb = ensure_return_bb;
 
@@ -4828,10 +4845,13 @@
 		BasicBlock *old_rescue_invoke_bb = rescue_invoke_bb;
 		BasicBlock *old_rescue_rethrow_bb = rescue_rethrow_bb;
 
+		Value *old_has_ensure =
+		    compile_set_has_ensure(ConstantInt::get(Int8Ty, 1));
+
 		rescue_invoke_bb = new_rescue_invoke_bb;
 		rescue_rethrow_bb = new_rescue_rethrow_bb;
 		DEBUG_LEVEL_INC();
-		val = compile_node(node->nd_head);
+		Value *val = compile_node(node->nd_head);
 		DEBUG_LEVEL_DEC();
 		rescue_rethrow_bb = old_rescue_rethrow_bb;
 		rescue_invoke_bb = old_rescue_invoke_bb;
@@ -4852,6 +4872,7 @@
 			BranchInst::Create(new_rescue_rethrow_bb, bb);
 		    }
 		    bb = new_rescue_rethrow_bb;
+		    compile_set_has_ensure(old_has_ensure);
 		    compile_node(node->nd_ensr);
 		    compile_rethrow_exception();
 		}
@@ -4869,6 +4890,7 @@
 		    // some value was returned in the block so we have to
 		    // make a version of the ensure that returns this value
 		    bb = ensure_return_bb;
+		    compile_set_has_ensure(old_has_ensure);
 		    compile_node(node->nd_ensr);
 		    // the return value is the PHINode from all the return
 		    compile_simple_return(new_ensure_pn);
@@ -4877,6 +4899,7 @@
 		// we also have to compile the ensure
 		// for when the block was left without return
 		bb = ensure_normal_bb;
+		compile_set_has_ensure(old_has_ensure);
 		compile_node(node->nd_ensr);
 
 		return val;
@@ -4973,9 +4996,9 @@
 		BasicBlock *return_from_block_bb = NULL;
 		if (!old_current_block_chain && return_from_block != -1) {
 		    // 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.
+		    // return expressions! We need to enclose further
+		    // dispatcher calls inside an exception handler, since
+		    // return-from-block may use a C++ exception.
 		    Function *f = bb->getParent();
 		    rescue_invoke_bb = return_from_block_bb =
 			BasicBlock::Create(context, "return-from-block", f);
@@ -5019,6 +5042,37 @@
 		    caller = compile_dispatch_call(params);
 		}
 
+		if (returnedFromBlockFunc == NULL) {
+		    // VALUE rb_vm_returned_from_block(int id);
+		    returnedFromBlockFunc = cast<Function>(
+			    module->getOrInsertFunction(
+				"rb_vm_returned_from_block",
+				RubyObjTy, Int32Ty, NULL));
+		}
+
+		std::vector<Value *> params2;
+		params2.push_back(ConstantInt::get(Int32Ty,
+			    return_from_block_bb != NULL
+			    ? return_from_block : -1));
+
+		Value *retval_block = CallInst::Create(returnedFromBlockFunc,
+			params2.begin(), params2.end(), "", bb);
+
+		Value *is_returned = new ICmpInst(*bb, ICmpInst::ICMP_NE,
+			retval_block, undefVal);
+
+		Function *f = bb->getParent();
+		BasicBlock *return_bb = BasicBlock::Create(context,
+			"return-from-block-fast", f);
+		BasicBlock *next_bb = BasicBlock::Create(context, "next", f);
+
+		BranchInst::Create(return_bb, next_bb, is_returned, bb);
+
+		bb = return_bb;
+		ReturnInst::Create(context, retval_block, bb);
+
+		bb = next_bb;
+
 		if (return_from_block_bb != NULL) {
 		    BasicBlock *old_bb = bb;
 		    bb = return_from_block_bb;

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2009-11-03 07:22:20 UTC (rev 2949)
+++ MacRuby/trunk/compiler.h	2009-11-04 06:05:31 UTC (rev 2950)
@@ -209,7 +209,9 @@
 	Function *getSpecialFunc;
 	Function *breakFunc;
 	Function *returnFromBlockFunc;
+	Function *returnedFromBlockFunc;
 	Function *checkReturnFromBlockFunc;
+	Function *setHasEnsureFunc;
 	Function *longjmpFunc;
 	Function *setjmpFunc;
 	Function *setScopeFunc;
@@ -308,6 +310,7 @@
 	Value *compile_dvar_slot(ID name);
 	void compile_break_val(Value *val);
 	void compile_simple_return(Value *val);
+	Value *compile_set_has_ensure(Value *val);
 	void compile_return_from_block(Value *val, int id);
 	void compile_return_from_block_handler(int id);
 	Value *compile_jump(NODE *node);

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2009-11-03 07:22:20 UTC (rev 2949)
+++ MacRuby/trunk/vm.cpp	2009-11-04 06:05:31 UTC (rev 2950)
@@ -271,6 +271,8 @@
     last_status = Qnil;
     errinfo = Qnil;
     parse_in_eval = false;
+    has_ensure = false;
+    return_from_block = -1;
 }
 
 static inline void *
@@ -327,6 +329,8 @@
     last_status = Qnil;
     errinfo = Qnil;
     parse_in_eval = false;
+    has_ensure = false;
+    return_from_block = -1;
 }
 
 RoxorVM::~RoxorVM(void)
@@ -3099,7 +3103,12 @@
 	rb_raise(rb_eLocalJumpError, "break from proc-closure");
     }
 #endif
-    GET_VM()->set_broken_with(val);
+    RoxorVM *vm = GET_VM();
+    if (vm->get_broken_with() != val) {
+	GC_RELEASE(vm->get_broken_with());
+	vm->set_broken_with(val);
+	GC_RETAIN(val);
+    }
 }
 
 extern "C"
@@ -3117,20 +3126,57 @@
 }
 
 extern "C"
+unsigned char
+rb_vm_set_has_ensure(unsigned char state)
+{
+    RoxorVM *vm = GET_VM();
+    const bool old_state = vm->get_has_ensure();
+    vm->set_has_ensure(state);
+    return old_state ? 1 : 0;
+}
+
+extern "C"
 void
 rb_vm_return_from_block(VALUE val, int id, rb_vm_block_t *running_block)
 {
+    RoxorVM *vm = GET_VM();
+
     // Do not trigger a return from the calling scope if the running block
     // is a lambda, to conform to the ruby 1.9 specifications.
-    if (!(running_block->flags & VM_BLOCK_LAMBDA)) {
+    if (running_block->flags & VM_BLOCK_LAMBDA) {
+	return;
+    }
+
+    // If we are inside an ensure block or if the running block is a Proc,
+    // let's implement return-from-block using a C++ exception (slow).
+    if (vm->get_has_ensure() || (running_block->flags & VM_BLOCK_PROC)) {
 	RoxorReturnFromBlockException *exc =
 	    new RoxorReturnFromBlockException();
 	exc->val = val;
 	exc->id = id;
 	throw exc;
     }
+
+    // Otherwise, let's mark the VM (fast).
+    vm->set_return_from_block(id);
+    if (vm->get_broken_with() != val) {
+	GC_RELEASE(vm->get_broken_with());
+	vm->set_broken_with(val);
+	GC_RETAIN(val);
+    }
 }
 
+extern "C"
+VALUE
+rb_vm_returned_from_block(int id)
+{
+    RoxorVM *vm = GET_VM();
+    if (id != -1 && vm->get_return_from_block() == id) {
+	vm->set_return_from_block(-1);
+    }
+    return vm->pop_broken_with();
+}
+
 extern "C" std::type_info *__cxa_current_exception_type(void);
 
 static inline bool
@@ -3558,7 +3604,7 @@
 {
     VALUE last_status = GET_VM()->get_last_status();
     if (last_status != Qnil) {
-	rb_objc_release((void *)last_status);
+	GC_RELEASE(last_status);
     }
 
     if (pid == -1) {
@@ -3568,7 +3614,7 @@
 	last_status = rb_obj_alloc(rb_cProcessStatus);
 	rb_iv_set(last_status, "status", INT2FIX(status));
 	rb_iv_set(last_status, "pid", PIDT2NUM(pid));
-	rb_objc_retain((void *)last_status);
+	GC_RETAIN(last_status);
     }
     GET_VM()->set_last_status(last_status);
 }
@@ -3588,10 +3634,10 @@
     }
     VALUE errinfo = GET_VM()->get_errinfo();
     if (errinfo != Qnil) {
-	rb_objc_release((void *)errinfo);
+	GC_RELEASE(errinfo);
     }
     GET_VM()->set_errinfo(err);
-    rb_objc_retain((void *)err);
+    GC_RETAIN(err);
 }
 
 extern "C"
@@ -3645,9 +3691,9 @@
 {
     VALUE old = GET_VM()->get_backref();
     if (old != val) {
-	rb_objc_release((void *)old);
+	GC_RELEASE(old);
 	GET_VM()->set_backref(val);
-	rb_objc_retain((void *)val);
+	GC_RETAIN(val);
     }
 }
 

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2009-11-03 07:22:20 UTC (rev 2949)
+++ MacRuby/trunk/vm.h	2009-11-04 06:05:31 UTC (rev 2950)
@@ -845,6 +845,8 @@
 	int safe_level;
 	rb_vm_method_missing_reason_t method_missing_reason;
 	bool parse_in_eval;
+	bool has_ensure;
+	int return_from_block;
 
     public:
 	RoxorVM(void);
@@ -861,6 +863,8 @@
 	ACCESSOR(safe_level, int);
 	ACCESSOR(method_missing_reason, rb_vm_method_missing_reason_t);
 	ACCESSOR(parse_in_eval, bool);
+	ACCESSOR(has_ensure, bool);
+	ACCESSOR(return_from_block, int);
 
 	std::string debug_blocks(void);
 
@@ -948,15 +952,18 @@
 
 	VALUE *get_binding_lvar(ID name, bool create);
 
+	VALUE ruby_catch(VALUE tag);
+	VALUE ruby_throw(VALUE tag, VALUE value);
+
 	VALUE pop_broken_with(void) {
-	    VALUE v = broken_with;
-	    broken_with = Qundef;
-	    return v;
+	    VALUE val = broken_with;
+	    if (return_from_block == -1) {
+		GC_RELEASE(val);
+		broken_with = Qundef;
+	    }
+	    return val;
 	}
 
-	VALUE ruby_catch(VALUE tag);
-	VALUE ruby_throw(VALUE tag, VALUE value);
-
 	void setup_from_current_thread(void);
 
 	VALUE exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20091103/79b44d50/attachment-0001.html>


More information about the macruby-changes mailing list