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
diff --git a/vm/builtin/nativemethod.cpp b/vm/builtin/nativemethod.cpp
index b989390..8f513ea 100644
--- a/vm/builtin/nativemethod.cpp
+++ b/vm/builtin/nativemethod.cpp
@@ -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
--- a/vm/exception.cpp
+++ b/vm/exception.cpp
@@ -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
--- a/vm/exception.hpp
+++ b/vm/exception.hpp
@@ -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
--- a/vm/subtend/ruby.cpp
+++ b/vm/subtend/ruby.cpp
@@ -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) {