[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