[macruby-changes] [3034] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Nov 19 23:47:31 PST 2009
Revision: 3034
http://trac.macosforge.org/projects/ruby/changeset/3034
Author: martinlagardette at apple.com
Date: 2009-11-19 23:47:28 -0800 (Thu, 19 Nov 2009)
Log Message:
-----------
- ruby catch/throw statements now use C++ exceptions instead of setjmp/longjmp
Modified Paths:
--------------
MacRuby/trunk/vm.cpp
MacRuby/trunk/vm.h
Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp 2009-11-19 07:36:31 UTC (rev 3033)
+++ MacRuby/trunk/vm.cpp 2009-11-20 07:47:28 UTC (rev 3034)
@@ -45,6 +45,8 @@
#include "dtrace.h"
#include <objc/objc-exception.h>
+#include <cxxabi.h>
+using namespace __cxxabiv1;
#include <execinfo.h>
#include <dlfcn.h>
@@ -332,6 +334,7 @@
parse_in_eval = false;
has_ensure = false;
return_from_block = -1;
+ throw_exc = NULL;
}
RoxorVM::~RoxorVM(void)
@@ -3148,7 +3151,7 @@
objc_exception_throw(ocexc);
}
else {
- __cxa_rethrow();
+ __cxa_rethrow();
}
}
#endif
@@ -3836,38 +3839,50 @@
VALUE
RoxorVM::ruby_catch(VALUE tag)
{
- std::map<VALUE, rb_vm_catch_t *>::iterator iter =
- catch_jmp_bufs.find(tag);
- rb_vm_catch_t *s = NULL;
- if (iter == catch_jmp_bufs.end()) {
- s = (rb_vm_catch_t *)malloc(sizeof(rb_vm_catch_t));
- s->throw_value = Qnil;
- s->nested = 1;
- catch_jmp_bufs[tag] = s;
+ std::map<VALUE, int*>::iterator iter = catch_nesting.find(tag);
+
+ int *nested_ptr = NULL;
+ if (iter == catch_nesting.end()) {
+ nested_ptr = (int *)malloc(sizeof(int));
+ *nested_ptr = 1;
+ catch_nesting[tag] = nested_ptr;
GC_RETAIN(tag);
}
else {
- s = iter->second;
- s->nested++;
+ nested_ptr = iter->second;
+ (*nested_ptr)++;
}
- VALUE retval;
- if (setjmp(s->buf) == 0) {
+ VALUE retval = Qundef;
+ try {
retval = rb_vm_yield(1, &tag);
}
- else {
- retval = s->throw_value;
- rb_objc_release((void *)retval);
- s->throw_value = Qnil;
+ catch (...) {
+ // Cannot catch "RoxorCatchThrowException *exc", otherwise the program
+ // will crash when trying to interpret ruby exceptions.
+ // So we catch ... instead, and retrieve the exception from the VM.
+ std::type_info *t = __cxa_current_exception_type();
+ if (t != NULL && *t == typeid(RoxorCatchThrowException *)) {
+ RoxorCatchThrowException *exc = GET_VM()->get_throw_exc();
+ if (exc != NULL && exc->throw_symbol == tag) {
+ retval = exc->throw_value;
+ rb_objc_release((void *)retval);
+ delete exc;
+ GET_VM()->set_throw_exc(NULL);
+ }
+ }
+ if (retval == Qundef) {
+ throw;
+ }
}
- iter = catch_jmp_bufs.find(tag);
- assert(iter != catch_jmp_bufs.end());
- s->nested--;
- if (s->nested == 0) {
- s = iter->second;
- free(s);
- catch_jmp_bufs.erase(iter);
+ iter = catch_nesting.find(tag);
+ assert(iter != catch_nesting.end());
+ (*nested_ptr)--;
+ if (*nested_ptr == 0) {
+ nested_ptr = iter->second;
+ free(nested_ptr);
+ catch_nesting.erase(iter);
GC_RELEASE(tag);
}
@@ -3884,20 +3899,24 @@
VALUE
RoxorVM::ruby_throw(VALUE tag, VALUE value)
{
- std::map<VALUE, rb_vm_catch_t *>::iterator iter =
- catch_jmp_bufs.find(tag);
- if (iter == catch_jmp_bufs.end()) {
+ std::map<VALUE, int*>::iterator iter = catch_nesting.find(tag);
+
+ if (iter == catch_nesting.end()) {
VALUE desc = rb_inspect(tag);
rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
}
- rb_vm_catch_t *s = iter->second;
rb_objc_retain((void *)value);
- s->throw_value = value;
- longjmp(s->buf, 1);
+ RoxorCatchThrowException *exc = new RoxorCatchThrowException;
+ exc->throw_symbol = tag;
+ exc->throw_value = value;
+ // There is no way - yet - to retrieve the exception from the ABI
+ // So instead, we store the exception in the VM
+ GET_VM()->set_throw_exc(exc);
+ throw exc;
- return Qnil; // never reached
+ return Qnil; // Never reached;
}
extern "C"
Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h 2009-11-19 07:36:31 UTC (rev 3033)
+++ MacRuby/trunk/vm.h 2009-11-20 07:47:28 UTC (rev 3034)
@@ -817,6 +817,13 @@
METHOD_MISSING_SUPER
} rb_vm_method_missing_reason_t;
+// Custome C++ exception for catch/throw blocks
+class RoxorCatchThrowException {
+ public:
+ VALUE throw_symbol;
+ VALUE throw_value;
+};
+
// 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.
@@ -854,7 +861,7 @@
std::vector<rb_vm_block_t *> current_blocks;
std::vector<VALUE> current_exceptions;
std::vector<rb_vm_binding_t *> bindings;
- std::map<VALUE, rb_vm_catch_t *> catch_jmp_bufs;
+ std::map<VALUE, int *> catch_nesting;
std::vector<VALUE> recursive_objects;
VALUE thread;
@@ -870,6 +877,8 @@
bool has_ensure;
int return_from_block;
+ RoxorCatchThrowException *throw_exc;
+
public:
RoxorVM(void);
RoxorVM(const RoxorVM &vm);
@@ -887,6 +896,7 @@
ACCESSOR(parse_in_eval, bool);
ACCESSOR(has_ensure, bool);
ACCESSOR(return_from_block, int);
+ ACCESSOR(throw_exc, RoxorCatchThrowException *);
std::string debug_blocks(void);
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20091119/d4e8db25/attachment.html>
More information about the macruby-changes
mailing list