Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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) {