Skip to content
Browse files

now properly popping exceptions from the VM stack when we unwind from…

… a handler, added blocks symbolication

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3372 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
1 parent 292c513 commit 23ef57efc8616d785d4ac46b71f4e9bfde75c37c Laurent Sansonetti committed Jan 30, 2010
Showing with 147 additions and 67 deletions.
  1. +24 −6 compiler.cpp
  2. +1 −1 compiler.h
  3. +109 −36 vm.cpp
  4. +13 −24 vm.h
View
30 compiler.cpp
@@ -1951,15 +1951,17 @@ RoxorCompiler::compile_landing_pad_header(const std::type_info &eh_type)
}
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 @@ RoxorCompiler::compile_node(NODE *node)
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 @@ RoxorCompiler::compile_node(NODE *node)
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;
View
2 compiler.h
@@ -321,7 +321,7 @@ class RoxorCompiler {
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);
View
145 vm.cpp
@@ -271,6 +271,7 @@ class RoxorJITManager : public JITMemoryManager, public JITEventListener {
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 @@ RoxorCore::delenda(Function *func)
#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 @@ RoxorCore::symbolize_call_address(void *addr, void **startp, char *path,
*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 @@ __vm_raise(void)
#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 @@ rb_vm_raise(VALUE exception)
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 @@ rb_rescue2(VALUE (*b_proc) (ANYARGS), VALUE data1,
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 @@ rb_vm_returned_from_block(int id)
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 @@ rb_vm_backtrace(int level)
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 @@ rb_vm_is_eh_active(int argc, ...)
extern "C"
void
-rb_vm_pop_exception(void)
+rb_vm_pop_exception(int pos)
{
GET_VM()->pop_current_exception();
}
@@ -4435,7 +4508,7 @@ rb_vm_thread_throw_kill(void)
// 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
View
37 vm.h
@@ -847,11 +847,18 @@ typedef enum {
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
@@ -1011,19 +1018,8 @@ class RoxorVM {
? Qnil : current_exceptions.back();
}
- void push_current_exception(VALUE exc) {
- assert(!NIL_P(exc));
- rb_objc_retain((void *)exc);
- current_exceptions.push_back(exc);
- }
-
- 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;
- }
+ void push_current_exception(VALUE exc);
+ void pop_current_exception(int pos=0);
VALUE *get_binding_lvar(ID name, bool create);
@@ -1048,13 +1044,6 @@ class RoxorVM {
#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_ */

0 comments on commit 23ef57e

Please sign in to comment.
Something went wrong with that request. Please try again.