[macruby-changes] [2012] MacRuby/branches/experimental
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jul 10 16:42:34 PDT 2009
Revision: 2012
http://trac.macosforge.org/projects/ruby/changeset/2012
Author: lsansonetti at apple.com
Date: 2009-07-10 16:42:33 -0700 (Fri, 10 Jul 2009)
Log Message:
-----------
a better exception-based implementation for return-from-block
Modified Paths:
--------------
MacRuby/branches/experimental/compiler.cpp
MacRuby/branches/experimental/compiler.h
MacRuby/branches/experimental/test_vm/block.rb
MacRuby/branches/experimental/vm.cpp
MacRuby/branches/experimental/vm.h
Modified: MacRuby/branches/experimental/compiler.cpp
===================================================================
--- MacRuby/branches/experimental/compiler.cpp 2009-07-10 01:56:08 UTC (rev 2011)
+++ MacRuby/branches/experimental/compiler.cpp 2009-07-10 23:42:33 UTC (rev 2012)
@@ -32,9 +32,9 @@
llvm::Module *RoxorCompiler::module = NULL;
RoxorCompiler *RoxorCompiler::shared = NULL;
-RoxorCompiler::RoxorCompiler(const char *_fname)
+RoxorCompiler::RoxorCompiler(void)
{
- fname = _fname;
+ fname = NULL;
inside_eval = false;
bb = NULL;
@@ -58,7 +58,8 @@
current_loop_end_bb = NULL;
current_loop_exit_val = NULL;
current_rescue = false;
- return_from_block = false;
+ return_from_block = -1;
+ return_from_block_ids = 0;
dispatcherFunc = NULL;
fastEqqFunc = NULL;
@@ -114,7 +115,7 @@
getSpecialFunc = NULL;
breakFunc = NULL;
returnFromBlockFunc = NULL;
- returnFromBlockValueFunc = NULL;
+ checkReturnFromBlockFunc = NULL;
longjmpFunc = NULL;
setjmpFunc = NULL;
popBrokenValue = NULL;
@@ -147,8 +148,8 @@
#endif
}
-RoxorAOTCompiler::RoxorAOTCompiler(const char *_fname)
- : RoxorCompiler(_fname)
+RoxorAOTCompiler::RoxorAOTCompiler(void)
+: RoxorCompiler()
{
cObject_gvar = NULL;
name2symFunc = NULL;
@@ -1445,32 +1446,40 @@
}
void
-RoxorCompiler::compile_return_from_block(Value *val)
+RoxorCompiler::compile_return_from_block(Value *val, int id)
{
if (returnFromBlockFunc == NULL) {
- // void rb_vm_return_from_block(VALUE val);
+ // void rb_vm_return_from_block(VALUE val, int id);
returnFromBlockFunc = cast<Function>(
module->getOrInsertFunction("rb_vm_return_from_block",
- Type::VoidTy, RubyObjTy, NULL));
+ Type::VoidTy, RubyObjTy, Type::Int32Ty, NULL));
}
std::vector<Value *> params;
params.push_back(val);
+ params.push_back(ConstantInt::get(Type::Int32Ty, id));
CallInst::Create(returnFromBlockFunc, params.begin(), params.end(), "", bb);
}
void
-RoxorCompiler::compile_return_from_block_handler(void)
+RoxorCompiler::compile_return_from_block_handler(int id)
{
- compile_landing_pad_header();
+ //const std::type_info &eh_type = typeid(RoxorReturnFromBlockException *);
+ //Value *exception = compile_landing_pad_header(eh_type);
+ Value *exception = compile_landing_pad_header();
- if (returnFromBlockValueFunc == NULL) {
- returnFromBlockValueFunc = cast<Function>(
+ if (checkReturnFromBlockFunc == NULL) {
+ // VALUE rb_vm_check_return_from_block_exc(void *exc, int id);
+ checkReturnFromBlockFunc = cast<Function>(
module->getOrInsertFunction(
- "rb_vm_pop_return_from_block_value",
- RubyObjTy, NULL));
+ "rb_vm_check_return_from_block_exc",
+ RubyObjTy, PtrTy, Type::Int32Ty, NULL));
}
- Value *val = CallInst::Create(returnFromBlockValueFunc, "", bb);
+ std::vector<Value *> params;
+ params.push_back(exception);
+ params.push_back(ConstantInt::get(Type::Int32Ty, id));
+ Value *val = CallInst::Create(checkReturnFromBlockFunc, params.begin(),
+ params.end(), "", bb);
Function *f = bb->getParent();
BasicBlock *ret_bb = BasicBlock::Create("ret", f);
@@ -1558,8 +1567,10 @@
compile_pop_exception();
}
if (within_block) {
- return_from_block = true;
- compile_return_from_block(val);
+ if (return_from_block == -1) {
+ return_from_block = return_from_block_ids++;
+ }
+ compile_return_from_block(val, return_from_block);
ReturnInst::Create(val, bb);
}
else {
@@ -1596,9 +1607,15 @@
return compile_current_class();
}
-void
+Value *
RoxorCompiler::compile_landing_pad_header(void)
{
+ return compile_landing_pad_header(typeid(void));
+}
+
+Value *
+RoxorCompiler::compile_landing_pad_header(const std::type_info &eh_type)
+{
Function *eh_exception_f = Intrinsic::getDeclaration(module,
Intrinsic::eh_exception);
Value *eh_ptr = CallInst::Create(eh_exception_f, "", bb);
@@ -1621,21 +1638,58 @@
}
params.push_back(new BitCastInst(__gxx_personality_v0_func,
PtrTy, "", bb));
- params.push_back(compile_const_pointer(NULL));
- CallInst::Create(eh_selector_f, params.begin(), params.end(),
- "", bb);
+ if (eh_type == typeid(void)) {
+ // catch (...)
+ params.push_back(compile_const_pointer(NULL));
+ }
+ else {
+ // catch (eh_type &exc)
+ params.push_back(compile_const_pointer((void *)&eh_type));
+ params.push_back(compile_const_pointer(NULL));
+ }
+ Value *eh_sel = CallInst::Create(eh_selector_f, params.begin(),
+ params.end(), "", bb);
+
+ if (eh_type != typeid(void)) {
+ // TODO: this doesn't work yet, the type id must be a GlobalVariable...
+#if __LP64__
+ Function *eh_typeid_for_f = Intrinsic::getDeclaration(module,
+ Intrinsic::eh_typeid_for_i64);
+#else
+ Function *eh_typeid_for_f = Intrinsic::getDeclaration(module,
+ Intrinsic::eh_typeid_for_i32);
+#endif
+ std::vector<Value *> params;
+ params.push_back(compile_const_pointer((void *)&eh_type));
+
+ Value *eh_typeid = CallInst::Create(eh_typeid_for_f, params.begin(),
+ params.end(), "", bb);
+
+ Function *f = bb->getParent();
+ BasicBlock *typeok_bb = BasicBlock::Create("typeok", f);
+ BasicBlock *nocatch_bb = BasicBlock::Create("nocatch", f);
+ Value *need_ret = new ICmpInst(ICmpInst::ICMP_EQ, eh_sel,
+ eh_typeid, "", bb);
+ BranchInst::Create(typeok_bb, nocatch_bb, need_ret, bb);
+
+ bb = nocatch_bb;
+ compile_rethrow_exception();
+
+ bb = typeok_bb;
+ }
+
Function *beginCatchFunc = NULL;
if (beginCatchFunc == NULL) {
// void *__cxa_begin_catch(void *);
beginCatchFunc = cast<Function>(
module->getOrInsertFunction("__cxa_begin_catch",
- Type::VoidTy, PtrTy, NULL));
+ PtrTy, PtrTy, NULL));
}
params.clear();
params.push_back(eh_ptr);
- CallInst::Create(beginCatchFunc, params.begin(), params.end(),
+ return CallInst::Create(beginCatchFunc, params.begin(), params.end(),
"", bb);
}
@@ -4245,7 +4299,6 @@
compile_landing_pad_header();
compile_node(node->nd_ensr);
compile_rethrow_exception();
- //compile_landing_pad_footer();
}
else {
val = compile_node(node->nd_head);
@@ -4331,7 +4384,7 @@
NODE *old_current_block_node = current_block_node;
ID old_current_mid = current_mid;
bool old_current_block = current_block;
- bool old_return_from_block = return_from_block;
+ int old_return_from_block = return_from_block;
BasicBlock *old_rescue_bb = rescue_bb;
current_mid = 0;
@@ -4342,7 +4395,7 @@
assert(Function::classof(block));
BasicBlock *return_from_block_bb = NULL;
- if (!old_return_from_block && return_from_block) {
+ if (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
@@ -4381,10 +4434,10 @@
caller = compile_dispatch_call(params);
}
- if (return_from_block_bb) {
+ if (return_from_block != -1) {
BasicBlock *old_bb = bb;
bb = return_from_block_bb;
- compile_return_from_block_handler();
+ compile_return_from_block_handler(return_from_block);
rescue_bb = old_rescue_bb;
bb = old_bb;
}
@@ -4415,10 +4468,10 @@
if (node->nd_head != NULL) {
compile_dispatch_arguments(node->nd_head, params, &argc);
}
- params.insert(params.begin(), ConstantInt::get(Type::Int32Ty, argc));
+ params.insert(params.begin(),
+ ConstantInt::get(Type::Int32Ty, argc));
- return CallInst::Create(yieldFunc, params.begin(),
- params.end(), "", bb);
+ return compile_protected_call(yieldFunc, params);
}
break;
Modified: MacRuby/branches/experimental/compiler.h
===================================================================
--- MacRuby/branches/experimental/compiler.h 2009-07-10 01:56:08 UTC (rev 2011)
+++ MacRuby/branches/experimental/compiler.h 2009-07-10 23:42:33 UTC (rev 2012)
@@ -30,9 +30,13 @@
static llvm::Module *module;
static RoxorCompiler *shared;
- RoxorCompiler(const char *fname);
+ RoxorCompiler(void);
virtual ~RoxorCompiler(void) { }
+ void set_fname(const char *_fname) {
+ fname = _fname;
+ }
+
Value *compile_node(NODE *node);
virtual Function *compile_main_function(NODE *node);
@@ -92,7 +96,8 @@
BasicBlock *current_loop_body_bb;
BasicBlock *current_loop_end_bb;
Value *current_loop_exit_val;
- bool return_from_block;
+ int return_from_block;
+ int return_from_block_ids;
Function *dispatcherFunc;
Function *fastEqqFunc;
@@ -148,7 +153,7 @@
Function *getSpecialFunc;
Function *breakFunc;
Function *returnFromBlockFunc;
- Function *returnFromBlockValueFunc;
+ Function *checkReturnFromBlockFunc;
Function *longjmpFunc;
Function *setjmpFunc;
Function *popBrokenValue;
@@ -229,8 +234,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);
+ void compile_return_from_block(Value *val, int id);
+ void compile_return_from_block_handler(int id);
Value *compile_jump(NODE *node);
virtual Value *compile_mcache(SEL sel, bool super);
virtual Value *compile_ccache(ID id);
@@ -248,7 +253,8 @@
virtual Value *compile_immutable_literal(VALUE val);
virtual Value *compile_global_entry(NODE *node);
- void compile_landing_pad_header(void);
+ Value *compile_landing_pad_header(void);
+ Value *compile_landing_pad_header(const std::type_info &eh_type);
void compile_landing_pad_footer(bool pop_exception=true);
void compile_rethrow_exception(void);
void compile_pop_exception(void);
@@ -286,7 +292,7 @@
class RoxorAOTCompiler : public RoxorCompiler {
public:
- RoxorAOTCompiler(const char *fname);
+ RoxorAOTCompiler(void);
Function *compile_main_function(NODE *node);
Modified: MacRuby/branches/experimental/test_vm/block.rb
===================================================================
--- MacRuby/branches/experimental/test_vm/block.rb 2009-07-10 01:56:08 UTC (rev 2011)
+++ MacRuby/branches/experimental/test_vm/block.rb 2009-07-10 23:42:33 UTC (rev 2012)
@@ -527,6 +527,39 @@
p bar
}
+assert ':ok', %{
+ def foo
+ begin
+ yield
+ ensure
+ p :ok
+ end
+ end
+ def bar
+ foo { return }
+ end
+ bar
+}
+
+assert 'false', %{
+ def foo(m); m.synchronize { return 42 }; end
+ m = Mutex.new
+ foo(m)
+ p m.locked?
+}
+
+assert ':ok', %{
+ def foo(v)
+ 1.times do
+ return true if v
+ return false
+ p :nok1
+ end
+ p :nok2
+ end
+ p :ok if !foo(false) and foo(true)
+}
+
assert ":ok\n:ok", %{
def foo
raise
Modified: MacRuby/branches/experimental/vm.cpp
===================================================================
--- MacRuby/branches/experimental/vm.cpp 2009-07-10 01:56:08 UTC (rev 2011)
+++ MacRuby/branches/experimental/vm.cpp 2009-07-10 23:42:33 UTC (rev 2012)
@@ -180,7 +180,7 @@
#define VALUE_TO_GV(v) (value2gv((VALUE)v))
extern "C" void *__cxa_allocate_exception(size_t);
-extern "C" void __cxa_throw(void *, void *, void *);
+extern "C" void __cxa_throw(void *, void *, void (*)(void*));
RoxorCore::RoxorCore(void)
{
@@ -237,7 +237,6 @@
safe_level = 0;
backref = Qnil;
broken_with = Qundef;
- returned_from_block = false;
last_status = Qnil;
errinfo = Qnil;
parse_in_eval = false;
@@ -293,7 +292,6 @@
backref = Qnil;
broken_with = Qundef;
- returned_from_block = false;
last_status = Qnil;
errinfo = Qnil;
parse_in_eval = false;
@@ -3835,6 +3833,45 @@
return val;
}
+extern "C"
+void
+rb_vm_return_from_block(VALUE val, int id)
+{
+ RoxorReturnFromBlockException *exc = new RoxorReturnFromBlockException();
+
+ rb_objc_retain((void *)val);
+ exc->val = val;
+ exc->id = id;
+
+ throw exc;
+}
+
+extern "C" std::type_info *__cxa_current_exception_type(void);
+
+static inline bool
+current_exception_is_return_from_block(void)
+{
+ const std::type_info *exc_type = __cxa_current_exception_type();
+ return exc_type != NULL
+ && *exc_type == typeid(RoxorReturnFromBlockException *);
+}
+
+extern "C"
+VALUE
+rb_vm_check_return_from_block_exc(RoxorReturnFromBlockException **pexc, int id)
+{
+ if (current_exception_is_return_from_block()) {
+ RoxorReturnFromBlockException *exc = *pexc;
+ if (id == -1 || exc->id == id) {
+ VALUE val = exc->val;
+ rb_objc_release((void *)val);
+ delete exc;
+ return val;
+ }
+ }
+ return Qundef;
+}
+
static inline void
rb_vm_rethrow(void)
{
@@ -3842,27 +3879,19 @@
__cxa_throw(exc, NULL, NULL);
}
+#if 0
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)
+rb_vm_pop_return_from_block_value(int id)
{
- if (GET_VM()->get_returned_from_block()) {
- GET_VM()->set_returned_from_block(false);
+ if (GET_VM()->check_return_from_block(id)) {
VALUE val = rb_vm_pop_broken_value();
assert(val != Qundef);
return val;
}
return Qundef;
}
+#endif
extern "C"
VALUE
@@ -4023,8 +4052,8 @@
rb_vm_init_compiler(void)
{
RoxorCompiler::shared = ruby_aot_compile
- ? new RoxorAOTCompiler("")
- : new RoxorCompiler("");
+ ? new RoxorAOTCompiler()
+ : new RoxorCompiler();
}
extern "C"
@@ -4041,8 +4070,10 @@
RoxorCompiler *compiler = RoxorCompiler::shared;
bool old_inside_eval = compiler->is_inside_eval();
- compiler->set_inside_eval(inside_eval);
+ compiler->set_inside_eval(inside_eval);
+ compiler->set_fname(fname);
Function *function = compiler->compile_main_function(node);
+ compiler->set_fname(NULL);
compiler->set_inside_eval(old_inside_eval);
if (binding != NULL) {
@@ -4514,7 +4545,8 @@
}
catch (...) {
VALUE exc;
- if (rb_vm_pop_return_from_block_value() != Qundef) {
+ if (current_exception_is_return_from_block()) {
+ // TODO: the exception is leaking!
exc = rb_exc_new2(rb_eLocalJumpError,
"unexpected return from Thread");
}
Modified: MacRuby/branches/experimental/vm.h
===================================================================
--- MacRuby/branches/experimental/vm.h 2009-07-10 01:56:08 UTC (rev 2011)
+++ MacRuby/branches/experimental/vm.h 2009-07-10 23:42:33 UTC (rev 2012)
@@ -750,7 +750,6 @@
VALUE current_top_object;
VALUE backref;
VALUE broken_with;
- bool returned_from_block;
VALUE last_status;
VALUE errinfo;
int safe_level;
@@ -767,7 +766,6 @@
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);
@@ -877,6 +875,13 @@
#define GET_VM() (RoxorVM::current())
#define GET_THREAD() (GetThreadPtr(GET_VM()->get_thread()))
+// Custom C++ exception class used to implement "return-from-block".
+class RoxorReturnFromBlockException {
+ public:
+ VALUE val;
+ int id;
+};
+
#endif /* __cplusplus */
#endif /* __VM_H_ */
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090710/55e60e8d/attachment-0001.html>
More information about the macruby-changes
mailing list