diff --git a/vm/builtin/nativemethod.cpp b/vm/builtin/nativemethod.cpp
index b989390..8f513ea 100644
@@ -101,7 +101,16 @@ namespace rubinius {
env->set_state(state);
NativeMethod* nm = as<NativeMethod>(msg.method);
- Object* ret = nm->call(state, env, msg);
+ Object* ret;
+
+ try {
+ ret = nm->call(state, env, msg);
+ } catch(SubtendException& e) {
+ Exception* exc = Exception::make_exception(
+ state, as<Class>(env->get_object(e.exc_handle)), e.reason);
+ state->thread_state()->raise_exception(exc);
+ ret = NULL;
+ }
env->set_current_native_frame(nmf.previous());
diff --git a/vm/exception.cpp b/vm/exception.cpp
index 2b6a506..cb4760f 100644
@@ -22,6 +22,16 @@ namespace rubinius {
// Not reached.
}
+ SubtendException::SubtendException(intptr_t exc_handle, const char* reason)
+ : exc_handle(exc_handle), reason(NULL)
+ {
+ if(reason) this->reason = strdup(reason);
+ }
+
+ void SubtendException::raise(intptr_t exc_handle, const char* reason) {
+ throw SubtendException(exc_handle, reason);
+ }
+
void Assertion::raise(const char* reason) {
VM* state = VM::current_state();
abort();
diff --git a/vm/exception.hpp b/vm/exception.hpp
index 40d2bb9..9755be0 100644
@@ -113,6 +113,19 @@ namespace rubinius {
*/
void show(STATE);
};
+
+ // @todo: should this subclass VMException?
+ class SubtendException {
+ public:
+
+ intptr_t exc_handle;
+ char* reason;
+
+ SubtendException(intptr_t exc_handle, const char* reason);
+ ~SubtendException() { if(reason) free(reason); }
+
+ static void raise(intptr_t exc_handle, const char* reason);
+ };
};
#endif
diff --git a/vm/subtend/ruby.cpp b/vm/subtend/ruby.cpp
index b7e3345..bd7f6bd 100644
@@ -20,6 +20,7 @@
#include "builtin/string.hpp"
#include "builtin/symbol.hpp"
+#include "vm/exception.hpp"
#include "vm/global_cache.hpp"
#include "vm/message.hpp"
#include "vm/object_utils.hpp"
@@ -49,6 +50,7 @@ using rubinius::NativeMethodEnvironment;
using rubinius::Object;
using rubinius::SendSite;
using rubinius::String;
+using rubinius::SubtendException;
using rubinius::Symbol;
using rubinius::VM;
@@ -936,8 +938,17 @@ extern "C" {
return value;
}
+#define RB_RAISE_BUFSIZE 256
+
void rb_raise(VALUE error_handle, const char* format_string, ...) {
- throw std::runtime_error(std::string("rb_raise: ") + format_string); /* Yeah, not 'exactly' correct. */
+ va_list args;
+ char reason[RB_RAISE_BUFSIZE];
+
+ va_start(args, format_string);
+ vsnprintf(reason, RB_RAISE_BUFSIZE, format_string, args);
+ va_end(args);
+
+ SubtendException::raise(error_handle, reason);
}
VALUE rb_require(const char* name) {