[macruby-changes] [3372] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Jan 29 17:31:56 PST 2010


Revision: 3372
          http://trac.macosforge.org/projects/ruby/changeset/3372
Author:   lsansonetti at apple.com
Date:     2010-01-29 17:31:55 -0800 (Fri, 29 Jan 2010)
Log Message:
-----------
now properly popping exceptions from the VM stack when we unwind from a handler, added blocks symbolication

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	2010-01-30 01:26:55 UTC (rev 3371)
+++ MacRuby/trunk/compiler.cpp	2010-01-30 01:31:55 UTC (rev 3372)
@@ -1951,15 +1951,17 @@
 }
 
 void
-RoxorCompiler::compile_pop_exception(void)
+RoxorCompiler::compile_pop_exception(int pos)
 {
     if (popExceptionFunc == NULL) {
-	// void rb_vm_pop_exception(void);
+	// void rb_vm_pop_exception(int pos);
 	popExceptionFunc = cast<Function>(
 		module->getOrInsertFunction("rb_vm_pop_exception", 
-		    VoidTy, NULL));
+		    VoidTy, Int32Ty, NULL));
     }
-    CallInst::Create(popExceptionFunc, "", bb);
+    std::vector<Value *> params;
+    params.push_back(ConstantInt::get(Int32Ty, pos));
+    CallInst::Create(popExceptionFunc, params.begin(), params.end(), "", bb);
 }
 
 void
@@ -4886,13 +4888,28 @@
 
 		    bb = handler_bb;
 		    assert(n->nd_body != NULL);
+
+		    // Compile the rescue handler within another exception
+		    // handler.
+		    BasicBlock *old_rescue_invoke_bb = rescue_invoke_bb;
+		    BasicBlock *new_rescue_invoke_bb =
+			BasicBlock::Create(context, "rescue", f);
+		    rescue_invoke_bb = new_rescue_invoke_bb;
+
 		    Value *header_val = compile_node(n->nd_body);
 		    handler_bb = bb;
 		    BranchInst::Create(merge_bb, bb);
-
 		    handlers.push_back(std::pair<Value *, BasicBlock *>
 			    (header_val, handler_bb));
 
+		    // If the handler raised an exception, pop the previous
+		    // one from the VM stack and rethrow.
+		    bb = new_rescue_invoke_bb;
+		    compile_landing_pad_header();
+		    compile_pop_exception(1);
+		    compile_rethrow_exception();
+		    rescue_invoke_bb = old_rescue_invoke_bb;
+
 		    bb = handler_bb = next_handler_bb;
 
 		    n = n->nd_head;
@@ -5050,7 +5067,8 @@
 		current_loop_begin_bb = loopBB;
 		current_loop_body_bb = bodyBB;
 		current_loop_end_bb = afterBB;
-		current_loop_exit_val = PHINode::Create(RubyObjTy, "loop_exit", afterBB);
+		current_loop_exit_val = PHINode::Create(RubyObjTy,
+			"loop_exit", afterBB);
 		current_loop_exit_val->addIncoming(nilVal, exitBB);
 
 		bb = bodyBB;

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-01-30 01:26:55 UTC (rev 3371)
+++ MacRuby/trunk/compiler.h	2010-01-30 01:31:55 UTC (rev 3372)
@@ -321,7 +321,7 @@
 	void compile_landing_pad_footer(bool pop_exception=true);
 	Value *compile_current_exception(void);
 	void compile_rethrow_exception(void);
-	void compile_pop_exception(void);
+	void compile_pop_exception(int pos=0);
 	Value *compile_lvar_slot(ID name);
 	bool compile_lvars(ID *tbl);
 	Value *compile_new_struct(Value *klass, std::vector<Value *> &fields);

Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp	2010-01-30 01:26:55 UTC (rev 3371)
+++ MacRuby/trunk/vm.cpp	2010-01-30 01:31:55 UTC (rev 3372)
@@ -271,6 +271,7 @@
 extern "C" void *__cxa_allocate_exception(size_t);
 extern "C" void __cxa_throw(void *, void *, void (*)(void *));
 extern "C" void __cxa_rethrow(void);
+extern "C" std::type_info *__cxa_current_exception_type(void);
 
 RoxorCore::RoxorCore(void)
 {
@@ -553,6 +554,25 @@
 #endif
 }
 
+// Dummy function to be used for debugging (in gdb).
+extern "C"
+void
+rb_symbolicate(void *addr)
+{
+    void *start = NULL;
+    char path[1000];
+    char name[100];
+    unsigned long ln = 0;
+    if (GET_CORE()->symbolize_call_address(addr, &start, path, sizeof path,
+		&ln, name, sizeof name)) {
+	printf("addr %p start %p selector %s location %s:%ld\n",
+		addr, start, name, path, ln);
+    }
+    else {
+	printf("addr %p unknown\n", addr);
+    }
+}
+
 bool
 RoxorCore::symbolize_call_address(void *addr, void **startp, char *path,
 	size_t path_len, unsigned long *ln, char *name, size_t name_len)
@@ -577,37 +597,40 @@
 	*startp = start;
     }
 
-    if (name != NULL || path != NULL || ln != NULL) {
-	std::map<IMP, rb_vm_method_node_t *>::iterator iter = 
-	    ruby_imps.find((IMP)start);
-	if (iter == ruby_imps.end()) {
-	    // TODO symbolize objc selectors
-	    return false;
-	}
-
-	rb_vm_method_node_t *node = iter->second;
+    if (f != NULL) {
 	if (ln != NULL) {
 	    *ln = 0;
-	    if (f != NULL) {
-		for (std::vector<RoxorFunction::Line>::iterator iter =
-			f->lines.begin(); iter != f->lines.end(); ++iter) {
-		    *ln = (*iter).line;
-		    if ((*iter).address <= (uintptr_t)addr) {
-			break;
-		    }
+	    for (std::vector<RoxorFunction::Line>::iterator iter =
+		    f->lines.begin(); iter != f->lines.end(); ++iter) {
+		*ln = (*iter).line;
+		if ((*iter).address <= (uintptr_t)addr) {
+		    break;
 		}
 	    }
 	}
 	if (path != NULL) {
-	    if (f != NULL && f->path.size() > 0) {
-		strncpy(path, f->path.c_str(), path_len);
+	    strncpy(path, f->path.c_str(), path_len);
+	}
+	if (name != NULL) {
+	    std::map<IMP, rb_vm_method_node_t *>::iterator iter = 
+		ruby_imps.find((IMP)start);
+	    if (iter == ruby_imps.end()) {
+		strncpy(name, "block", name_len);
 	    }
 	    else {
-		strncpy(path, "core", path_len);
+		strncpy(name, sel_getName(iter->second->sel), name_len);
 	    }
 	}
+    }
+    else {
+	if (ln != NULL) {
+	    *ln = 0;
+	}
+	if (path != NULL) {
+	    strncpy(path, "core", path_len);
+	}
 	if (name != NULL) {
-	    strncpy(name, sel_getName(node->sel), name_len);
+	    name[0] = '\0';
 	}
     }
 
@@ -3426,6 +3449,61 @@
 #endif
 }
 
+void
+RoxorVM::push_current_exception(VALUE exc)
+{
+    assert(!NIL_P(exc));
+    rb_objc_retain((void *)exc);
+    current_exceptions.push_back(exc);
+//printf("PUSH %p %s\n", (void *)exc, RSTRING_PTR(rb_inspect(exc)));
+}
+
+class RoxorThreadRaiseException {
+};
+
+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 *);
+}
+
+static inline bool
+current_exception_is_catch_throw(void)
+{
+    const std::type_info *exc_type = __cxa_current_exception_type();
+    return exc_type != NULL
+	&& *exc_type == typeid(RoxorCatchThrowException *);
+}
+
+static inline bool
+current_exception_is_thread_raise(void)
+{
+    const std::type_info *exc_type = __cxa_current_exception_type();
+    return exc_type != NULL
+	&& *exc_type == typeid(RoxorThreadRaiseException *);
+}
+
+void
+RoxorVM::pop_current_exception(int pos)
+{
+    if (current_exception_is_return_from_block()
+	|| current_exception_is_catch_throw()
+	|| current_exception_is_thread_raise()) {
+	return;
+    }
+
+    assert((size_t)pos < current_exceptions.size());
+
+    std::vector<VALUE>::iterator iter = current_exceptions.end() - (pos + 1);
+    VALUE exc = *iter;
+    current_exceptions.erase(iter);
+
+    rb_objc_release((void *)exc);
+//printf("POP (%d) %p %s\n", pos, (void *)exc, RSTRING_PTR(rb_inspect(exc)));
+}
+
 #if !__LP64__
 extern "C"
 void
@@ -3465,13 +3543,14 @@
 extern "C"
 VALUE
 rb_rescue2(VALUE (*b_proc) (ANYARGS), VALUE data1,
-           VALUE (*r_proc) (ANYARGS), VALUE data2, ...)
+	VALUE (*r_proc) (ANYARGS), VALUE data2, ...)
 {
     try {
 	return (*b_proc)(data1);
     }
     catch (...) {
-	VALUE exc = rb_vm_current_exception();
+	RoxorVM *vm = GET_VM();
+	VALUE exc = vm->current_exception();
 	if (exc != Qnil) {
 	    va_list ar;
 	    VALUE eclass;
@@ -3487,8 +3566,9 @@
 	    va_end(ar);
 
 	    if (handled) {
+		vm->pop_current_exception();
 		if (r_proc != NULL) {
-		    return (*r_proc)(data2);
+		    return (*r_proc)(data2, exc);
 		}
 		return Qnil;
 	    }
@@ -3604,16 +3684,6 @@
     return vm->pop_broken_with();
 }
 
-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)
@@ -3652,8 +3722,11 @@
 	char name[100];
 	unsigned long ln = 0;
 
+	path[0] = name[0] = '\0';
+
 	if (GET_CORE()->symbolize_call_address(callstack[i], NULL,
-		    path, sizeof path, &ln, name, sizeof name)) {
+		    path, sizeof path, &ln, name, sizeof name)
+		&& name[0] != '\0') {
 	    char entry[PATH_MAX];
 	    if (ln == 0) {
 		snprintf(entry, sizeof entry, "%s:in `%s'",
@@ -3709,7 +3782,7 @@
 
 extern "C"
 void
-rb_vm_pop_exception(void)
+rb_vm_pop_exception(int pos)
 {
     GET_VM()->pop_current_exception();
 }
@@ -4435,7 +4508,7 @@
     // Killing a thread is implemented using a non-catchable (from Ruby)
     // exception, which allows us to call the ensure blocks before dying,
     // which is unfortunately covered in the Ruby specifications.
-    rb_vm_rethrow();
+    throw new RoxorThreadRaiseException();
 }
 
 static void

Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h	2010-01-30 01:26:55 UTC (rev 3371)
+++ MacRuby/trunk/vm.h	2010-01-30 01:31:55 UTC (rev 3372)
@@ -847,13 +847,20 @@
     METHOD_MISSING_SUPER
 } rb_vm_method_missing_reason_t;
 
-// Custome C++ exception for catch/throw blocks
+// Custom C++ exception class for catch/throw blocks.
 class RoxorCatchThrowException {
- public:
-    VALUE throw_symbol;
-    VALUE throw_value;
+    public:
+	VALUE throw_symbol;
+	VALUE throw_value;
 };
 
+// Custom C++ exception class used to implement "return-from-block".
+class RoxorReturnFromBlockException {
+    public:
+	VALUE val;
+	int id;
+};
+
 // The VM class is instantiated per thread. There is always at least one
 // instance. The VM class is purely thread-safe and concurrent, it does not
 // acquire any lock, except when it calls the Core.
@@ -1011,20 +1018,9 @@
 		? Qnil : current_exceptions.back();
 	}
 
-	void push_current_exception(VALUE exc) {
-	    assert(!NIL_P(exc));
-	    rb_objc_retain((void *)exc);
-	    current_exceptions.push_back(exc);
-	}
+	void push_current_exception(VALUE exc);
+	void pop_current_exception(int pos=0);
 
-	VALUE pop_current_exception(void) {
-	    assert(!current_exceptions.empty());
-	    VALUE exc = current_exceptions.back();
-	    rb_objc_release((void *)exc);
-	    current_exceptions.pop_back();
-	    return exc;
-	}
-
 	VALUE *get_binding_lvar(ID name, bool create);
 
 	VALUE ruby_catch(VALUE tag);
@@ -1048,13 +1044,6 @@
 #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/20100129/2b2e6885/attachment-0001.html>


More information about the macruby-changes mailing list