diff --git a/vm/builtin/nativemethod.cpp b/vm/builtin/nativemethod.cpp
index b989390..0a1f6df 100644
--- a/vm/builtin/nativemethod.cpp
+++ b/vm/builtin/nativemethod.cpp
@@ -2,6 +2,9 @@

#include "vm.hpp"

+#include "exception.hpp"
+#include "exception_point.hpp"
+#include "message.hpp"
#include "native_libraries.hpp"
#include "primitives.hpp"

@@ -11,8 +14,6 @@
#include "builtin/string.hpp"
#include "builtin/tuple.hpp"

-#include "message.hpp"
-
namespace rubinius {

typedef TypedRoot<Object*> RootHandle;
@@ -91,7 +92,6 @@ namespace rubinius {
return create<GenericFunctor>(state);
}

-
Object* NativeMethod::executor_implementation(STATE, CallFrame* call_frame, Message& msg) {
NativeMethodEnvironment* env = native_method_environment.get();
NativeMethodFrame nmf(env->current_native_frame());
@@ -101,9 +101,20 @@ namespace rubinius {
env->set_state(state);

NativeMethod* nm = as<NativeMethod>(msg.method);
- Object* ret = nm->call(state, env, msg);
+
+ Object* ret;
+ ExceptionPoint ep(env);
+
+ PLACE_EXCEPTION_POINT(ep);
+
+ if(unlikely(ep.jumped_to())) {
+ ret = NULL;
+ } else {
+ ret = nm->call(state, env, msg);
+ }

env->set_current_native_frame(nmf.previous());
+ ep.pop(env);

return ret;
}
@@ -256,6 +267,4 @@ namespace rubinius {
}
}

-
-
}
diff --git a/vm/builtin/nativemethod.hpp b/vm/builtin/nativemethod.hpp
index 028329b..c57728a 100644
--- a/vm/builtin/nativemethod.hpp
+++ b/vm/builtin/nativemethod.hpp
@@ -20,6 +20,7 @@
namespace rubinius {

/* Forwards */
+ class ExceptionPoint;
class Message;
class NativeMethodFrame;

@@ -99,6 +100,14 @@ namespace rubinius {
current_native_frame_ = frame;
}

+ ExceptionPoint* current_ep() {
+ return current_ep_;
+ }
+
+ void set_current_ep(ExceptionPoint* ep) {
+ current_ep_ = ep;
+ }
+
/** Set of Handles available in current Frame (convenience.) */
Handles& handles();

@@ -113,6 +122,7 @@ namespace rubinius {
NativeMethodFrame* current_native_frame_;
/** Global object handles. */
Handles global_handles_;
+ ExceptionPoint* current_ep_;
};


diff --git a/vm/exception_point.cpp b/vm/exception_point.cpp
new file mode 100644
index 0000000..8cddf16
--- /dev/null
+++ b/vm/exception_point.cpp
@@ -0,0 +1,22 @@
+#include "exception_point.hpp"
+#include "builtin/nativemethod.hpp"
+
+namespace rubinius {
+ ExceptionPoint::ExceptionPoint(NativeMethodEnvironment* env)
+ : jumped_to_(false)
+ , previous_(env->current_ep())
+ {
+ env->set_current_ep(this);
+ }
+
+ void ExceptionPoint::return_to(NativeMethodEnvironment* env) {
+ jumped_to_ = true;
+ env->set_current_ep(this);
+ _longjmp(__jump_buffer, 1);
+ abort(); // HUH!
+ }
+
+ void ExceptionPoint::pop(NativeMethodEnvironment* env) {
+ env->set_current_ep(previous_);
+ }
+}
diff --git a/vm/exception_point.hpp b/vm/exception_point.hpp
index 5571c26..075bd84 100644
--- a/vm/exception_point.hpp
+++ b/vm/exception_point.hpp
@@ -3,6 +3,8 @@
#include <setjmp.h>

namespace rubinius {
+ class NativeMethodEnvironment;
+
class ExceptionPoint {
bool jumped_to_;
ExceptionPoint* previous_;
@@ -11,12 +13,7 @@ namespace rubinius {
jmp_buf __jump_buffer;

public:
- ExceptionPoint(Task* task)
- : jumped_to_(false)
- , previous_(task->current_ep)
- {
- task->current_ep = this;
- }
+ ExceptionPoint(NativeMethodEnvironment* env);

bool jumped_to() {
return jumped_to_;
@@ -26,23 +23,16 @@ namespace rubinius {
jumped_to_ = false;
}

- void return_to(Task* task) {
- jumped_to_ = true;
- task->current_ep = this;
- _longjmp(__jump_buffer, 1);
- abort(); // HUH!
- }
-
- void unwind_to_previous(Task* task) {
- previous_->return_to(task);
- }
+ void return_to(NativeMethodEnvironment* env);

- void pop(Task* task) {
- task->current_ep = previous_;
+ void unwind_to_previous(NativeMethodEnvironment* env) {
+ previous_->return_to(env);
}

+ void pop(NativeMethodEnvironment* env);
};
}
-#define PLACE_EXCEPTIONPOINT(ep) _setjmp(ep.__jump_buffer)
+
+#define PLACE_EXCEPTION_POINT(ep) _setjmp(ep.__jump_buffer)

#endif
diff --git a/vm/subtend/ruby.cpp b/vm/subtend/ruby.cpp
index b7e3345..3a56ecb 100644
--- a/vm/subtend/ruby.cpp
+++ b/vm/subtend/ruby.cpp
@@ -20,6 +20,8 @@
#include "builtin/string.hpp"
#include "builtin/symbol.hpp"

+#include "vm/exception.hpp"
+#include "vm/exception_point.hpp"
#include "vm/global_cache.hpp"
#include "vm/message.hpp"
#include "vm/object_utils.hpp"
@@ -38,6 +40,7 @@ using rubinius::ByteArray;
using rubinius::Class;
using rubinius::ClassType;
using rubinius::Data;
+using rubinius::Exception;
using rubinius::Fixnum;
using rubinius::Integer;
using rubinius::Message;
@@ -936,8 +939,22 @@ 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);
+
+ NativeMethodEnvironment* env = NativeMethodEnvironment::get();
+ Exception* exc = Exception::make_exception(
+ env->state(), as<Class>(env->get_object(error_handle)), reason);
+ env->state()->thread_state()->raise_exception(exc);
+
+ env->current_ep()->return_to(env);
}

VALUE rb_require(const char* name) {