public
Description: Johnson wraps JavaScript in a loving Ruby embrace.
Homepage: http://github.com/jbarnette/johnson/wikis
Clone URL: git://github.com/jbarnette/johnson.git
Runtime is the new Context. One context per Ruby thread.
jbarnette (author)
Fri May 30 17:18:16 -0700 2008
commit  ae3584f2d4e47d82c063c89631bcd8b23acfd9db
tree    019aa9a9739d6de9d366bad61e894779f48d5a2a
parent  794e0ac850a2b7e90feeb27c48267194e1c99be8
...
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
...
101
102
103
104
105
 
 
106
107
108
...
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
...
206
207
208
209
 
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
 
230
231
232
...
241
242
243
244
245
246
247
248
 
249
250
251
...
6
7
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
10
11
...
13
14
15
 
 
16
17
18
19
20
...
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
...
90
91
92
 
93
94
95
 
 
 
 
 
 
 
 
 
96
 
 
97
98
99
100
101
 
102
103
104
105
...
114
115
116
 
 
 
 
 
117
118
119
120
0
@@ -6,94 +6,6 @@
0
 #include "idhash.h"
0
 #include "jsdbgapi.h"
0
 
0
-/*
0
- * call-seq:
0
- *   global
0
- *
0
- * Returns the global object used for this context.
0
- */
0
-static VALUE global(VALUE self)
0
-{
0
-  OurContext* context;
0
-  Data_Get_Struct(self, OurContext, context);
0
-  return convert_to_ruby(context, OBJECT_TO_JSVAL(context->global));
0
-}
0
-
0
-/*
0
- * call-seq:
0
- *   evaluate(script, filename=nil, linenum=nil)
0
- *
0
- * Evaluate +script+ with +filename+ using +linenum+
0
- */
0
-static VALUE evaluate(int argc, VALUE* argv, VALUE self)
0
-{
0
-  VALUE script, filename, linenum;
0
-
0
-  OurContext* context;
0
-  Data_Get_Struct(self, OurContext, context);
0
-
0
-  rb_scan_args( argc, argv, "12", &script, &filename, &linenum );
0
-
0
-  // clean things up first
0
-  context->ex = 0;
0
-  memset(context->msg, 0, MAX_EXCEPTION_MESSAGE_SIZE);
0
-
0
-  const char* filenamez = RTEST(filename) ? StringValueCStr(filename) : "none";
0
-  int linenumi = RTEST(linenum) ? NUM2INT(linenum) : 1;
0
-
0
-  jsval js;
0
-
0
-  // FIXME: should be able to pass in the 'file' name
0
-  JSBool ok = JS_EvaluateScript(context->js, context->global,
0
-    StringValuePtr(script), (unsigned)StringValueLen(script), filenamez, (unsigned)linenumi, &js);
0
-
0
-  if (!ok)
0
-  {
0
-    if (JS_IsExceptionPending(context->js))
0
-    {
0
-      // If there's an exception pending here, it's a syntax error.
0
-      JS_GetPendingException(context->js, &context->ex);
0
-      JS_ClearPendingException(context->js);
0
-    }
0
-
0
-    if (context->ex)
0
-    {
0
-      return rb_funcall(self, rb_intern("handle_js_exception"),
0
-        1, convert_to_ruby(context, context->ex));
0
-      
0
-      // VALUE message, file, line, stack;
0
-      // 
0
-      // jsval js_message;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "message", &js_message));
0
-      // message = convert_to_ruby(context, js_message);
0
-      // 
0
-      // jsval js_file;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "fileName", &js_file));
0
-      // file = convert_to_ruby(context, js_file);
0
-      // 
0
-      // jsval js_line;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "lineNumber", &js_line));
0
-      // line = convert_to_ruby(context, js_line);
0
-      // 
0
-      // jsval js_stack;
0
-      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "stack", &js_stack));
0
-      // stack = convert_to_ruby(context, js_stack);
0
-      // 
0
-      // return rb_funcall(self, rb_intern("handle_js_exception"),
0
-      //   4, message, file, line, stack);
0
-    }
0
-    
0
-    char* msg = context->msg;
0
-
0
-    // toString() whatever the exception object is (if we have one)
0
-    if (context->ex) msg = JS_GetStringBytes(JS_ValueToString(context->js, context->ex));
0
-
0
-    return Johnson_Error_raise(msg);
0
-  }
0
-
0
-  return convert_to_ruby(context, js);
0
-}
0
-
0
 // callback for JS_SetErrorReporter
0
 static void report_js_error(JSContext* js, const char* message, JSErrorReport* UNUSED(report))
0
 {
0
@@ -101,8 +13,8 @@ static void report_js_error(JSContext* js, const char* message, JSErrorReport* U
0
   VALUE self = (VALUE)JS_GetContextPrivate(js);
0
 
0
   // then we find our bridge
0
-  OurContext* context;
0
-  Data_Get_Struct(self, OurContext, context);
0
+  JohnsonContext* context;
0
+  Data_Get_Struct(self, JohnsonContext, context);
0
 
0
   // NOTE: SpiderMonkey REALLY doesn't like being interrupted. If we
0
   // jump over to Ruby and raise here, segfaults and such ensue.
0
@@ -124,80 +36,52 @@ static JSBool branch_callback(JSContext* js, JSScript* UNUSED(script))
0
 
0
 /*
0
  * call-seq:
0
- *   debugger=(debugger)
0
+ *   native_initialize(options={})
0
  *
0
- * Sets a debugger object
0
+ * Initializes the native spidermonkey values.
0
  */
0
 static VALUE
0
-set_debugger(VALUE self, VALUE debugger)
0
+initialize_native(VALUE self, VALUE rb_runtime, VALUE UNUSED(options))
0
 {
0
-  OurContext* context;
0
-  JSDebugHooks* debug_hooks;
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
 
0
-  Data_Get_Struct(self, OurContext, context);
0
-  Data_Get_Struct(debugger, JSDebugHooks, debug_hooks);
0
+  Data_Get_Struct(self, JohnsonContext, context);
0
+  Data_Get_Struct(rb_runtime, JohnsonRuntime, runtime);
0
 
0
-  JS_SetContextDebugHooks(context->js, debug_hooks);
0
+  if ((context->js = JS_NewContext(runtime->js, 8192)))
0
+  {
0
+    // See if the runtime already has a shared global object.
0
+    JSObject* global = runtime->global;
0
 
0
-  return debugger;
0
-}
0
+    // If it does, use it. If not,
0
+    if (!global)
0
+      // create one of our global objects.
0
+      global = johnson_create_global_object(context->js);
0
 
0
-/*
0
- * call-seq:
0
- *   native_initialize(options={})
0
- *
0
- * Initializes the native spidermonkey values.
0
- */
0
-static VALUE
0
-initialize_native(VALUE self, VALUE UNUSED(options))
0
-{
0
-  OurContext* context;
0
-  bool gthings_rooted_p = false;
0
-
0
-  Data_Get_Struct(self, OurContext, context);
0
-
0
-  if ((context->runtime = JS_NewRuntime(0x100000))
0
-    && (context->js = JS_NewContext(context->runtime, 8192))
0
-    && (context->jsids = create_id_hash())
0
-    && (context->rbids = create_id_hash())
0
-    && (context->gcthings = JS_NewObject(context->js, NULL, 0, 0))
0
-    && (gthings_rooted_p = JS_AddNamedRoot(context->js, &(context->gcthings), "context->gcthings"))
0
-    && (context->global = create_global_object(context))
0
-    && (JS_AddNamedRoot(context->js, &(context->global), "context->global")))
0
-  {
0
+    // Manually set the context's global object.
0
+    JS_SetGlobalObject(context->js, global);
0
     JS_SetErrorReporter(context->js, report_js_error);
0
     JS_SetBranchCallback(context->js, branch_callback);
0
     JS_SetContextPrivate(context->js, (void *)self);
0
 
0
     JS_SetOptions(context->js, JS_GetOptions(context->js)
0
 #ifdef JSOPTION_DONT_REPORT_UNCAUGHT
0
-      | JSOPTION_DONT_REPORT_UNCAUGHT
0
+        | JSOPTION_DONT_REPORT_UNCAUGHT
0
 #endif
0
 #ifdef JSOPTION_VAROBJFIX
0
-      | JSOPTION_VAROBJFIX
0
+        | JSOPTION_VAROBJFIX
0
 #endif
0
 #ifdef JSOPTION_XML
0
-      | JSOPTION_XML
0
+        | JSOPTION_XML
0
 #endif
0
-    );
0
+        );
0
 
0
+    // Success.
0
     return init_spidermonkey_extensions(context, self);
0
   }
0
 
0
-  if (gthings_rooted_p)
0
-    JS_RemoveRoot(context->js, &(context->gcthings));
0
-
0
-  if (context->rbids)
0
-    JS_HashTableDestroy(context->rbids);
0
-
0
-  if (context->jsids)
0
-    JS_HashTableDestroy(context->jsids);
0
-
0
-  if (context->js)
0
-    JS_DestroyContext(context->js);
0
-
0
-  if (context->runtime)
0
-    JS_DestroyRuntime(context->runtime);
0
+  if (context->js) JS_DestroyContext(context->js);
0
 
0
   rb_raise(rb_eRuntimeError, "Failed to initialize SpiderMonkey context");
0
 }
0
@@ -206,27 +90,16 @@ initialize_native(VALUE self, VALUE UNUSED(options))
0
 //// INFRASTRUCTURE BELOW HERE ////////////////////////////////////////////
0
 ///////////////////////////////////////////////////////////////////////////
0
 
0
-static void deallocate(OurContext* context)
0
+static void deallocate(JohnsonContext* context)
0
 {
0
   JS_SetContextPrivate(context->js, 0);
0
-
0
-  JS_RemoveRoot(context->js, &(context->global));
0
-  JS_RemoveRoot(context->js, &(context->gcthings));
0
-  JS_HashTableDestroy(context->rbids);
0
-  JS_HashTableDestroy(context->jsids);
0
-
0
-  context->jsids = 0;
0
-  context->rbids = 0;
0
-
0
   JS_DestroyContext(context->js);
0
-  JS_DestroyRuntime(context->runtime);
0
-
0
   free(context);
0
 }
0
 
0
 static VALUE allocate(VALUE klass)
0
 {
0
-  OurContext* context = calloc(1, sizeof(OurContext));
0
+  JohnsonContext* context = calloc(1, sizeof(JohnsonContext));
0
   return Data_Wrap_Struct(klass, 0, deallocate, context);
0
 }
0
 
0
@@ -241,11 +114,7 @@ void init_Johnson_SpiderMonkey_Context(VALUE spidermonkey)
0
   VALUE context = rb_define_class_under(spidermonkey, "Context", rb_cObject);
0
 
0
   rb_define_alloc_func(context, allocate);
0
-  rb_define_private_method(context, "initialize_native", initialize_native, 1);
0
-
0
-  rb_define_method(context, "global", global, 0);
0
-  rb_define_method(context, "evaluate", evaluate, -1);
0
-  rb_define_method(context, "debugger=", set_debugger, 1);
0
+  rb_define_private_method(context, "initialize_native", initialize_native, 2);
0
 }
0
 
0
 VALUE Johnson_SpiderMonkey_JSLandProxy()
...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
21
22
23
...
7
8
9
 
 
 
 
 
 
10
11
12
13
 
14
15
16
17
0
@@ -7,17 +7,11 @@
0
 
0
 typedef struct {
0
   JSContext *js;
0
-  JSObject *global;
0
-  JSRuntime *runtime;
0
-  
0
-  JSHashTable *jsids; // jsid -> rbid
0
-  JSHashTable *rbids; // rbid -> jsid
0
-  JSObject *gcthings;
0
   
0
   jsval ex; // an exception value
0
   char msg[MAX_EXCEPTION_MESSAGE_SIZE]; // the 'backup' message
0
   
0
-} OurContext;
0
+} JohnsonContext;
0
 
0
 void init_Johnson_SpiderMonkey_Context(VALUE spidermonkey);
0
 VALUE Johnson_SpiderMonkey_JSLandProxy();
...
3
4
5
6
 
7
8
9
...
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
...
54
55
56
57
 
58
 
59
60
61
...
72
73
74
75
 
76
77
78
...
87
88
89
90
 
91
92
93
 
94
95
96
...
99
100
101
102
 
103
104
105
 
106
107
108
109
 
110
111
112
 
113
114
115
...
119
120
121
122
 
123
 
124
125
126
...
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
...
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
...
218
219
220
221
 
222
223
 
 
 
224
225
226
227
228
 
 
 
 
229
230
231
232
 
 
233
234
 
235
236
 
237
238
239
 
240
241
242
243
244
245
 
246
 
247
248
249
...
252
253
254
255
 
256
257
 
258
259
260
...
263
264
265
266
 
267
268
 
269
270
271
...
3
4
5
 
6
7
8
9
...
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
...
57
58
59
 
60
61
62
63
64
65
...
76
77
78
 
79
80
81
82
...
91
92
93
 
94
95
96
 
97
98
99
100
...
103
104
105
 
106
107
108
 
109
110
111
112
 
113
114
115
 
116
117
118
119
...
123
124
125
 
126
127
128
129
130
131
...
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
...
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
...
228
229
230
 
231
232
 
233
234
235
236
 
 
 
 
237
238
239
240
241
242
 
 
243
244
245
 
246
247
 
248
249
250
 
251
252
253
254
255
256
 
257
258
259
260
261
262
...
265
266
267
 
268
269
 
270
271
272
273
...
276
277
278
 
279
280
 
281
282
283
284
0
@@ -3,7 +3,7 @@
0
 #include "ruby_land_proxy.h"
0
 #include "error.h"
0
 
0
-DEFINE_RUBY_WRAPPER(convert_to_ruby, convert_to_ruby, ARGLIST2(context, js_value))
0
+DEFINE_RUBY_WRAPPER(convert_to_ruby, convert_to_ruby, ARGLIST2(runtime, js_value))
0
 
0
 DECLARE_RUBY_WRAPPER(rb_funcall_0, VALUE obj; ID sym; int argc)
0
 DEFINE_RUBY_WRAPPER(rb_funcall_0, rb_funcall, ARGLIST3(obj, sym, argc))
0
@@ -11,37 +11,40 @@ DEFINE_RUBY_WRAPPER(rb_funcall_0, rb_funcall, ARGLIST3(obj, sym, argc))
0
 DECLARE_RUBY_WRAPPER(rb_funcall_2, VALUE obj; ID sym; int argc; VALUE a; VALUE b)
0
 DEFINE_RUBY_WRAPPER(rb_funcall_2, rb_funcall, ARGLIST5(obj, sym, argc, a, b))
0
 
0
-static JSBool convert_float_or_bignum_to_js(OurContext* context, VALUE float_or_bignum, jsval* retval)
0
+static JSBool convert_float_or_bignum_to_js(JohnsonRuntime* runtime, VALUE float_or_bignum, jsval* retval)
0
 {
0
-  return JS_NewDoubleValue(context->js, NUM2DBL(float_or_bignum), retval);
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+  return JS_NewDoubleValue(context, NUM2DBL(float_or_bignum), retval);
0
 }
0
 
0
-static JSBool convert_symbol_to_js(OurContext* context, VALUE symbol, jsval* retval)
0
+static JSBool convert_symbol_to_js(JohnsonRuntime* runtime, VALUE symbol, jsval* retval)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   PREPARE_JROOTS(context, 2);
0
 
0
   VALUE to_s = CALL_RUBY_WRAPPER(rb_funcall_0, symbol, rb_intern("to_s"), 0);
0
-  jsval name = STRING_TO_JSVAL(JS_NewStringCopyN(context->js, StringValuePtr(to_s), (unsigned) StringValueLen(to_s)));
0
+  jsval name = STRING_TO_JSVAL(JS_NewStringCopyN(context, StringValuePtr(to_s), (unsigned) StringValueLen(to_s)));
0
 
0
   JROOT(name);
0
 
0
   // calls Johnson.symbolize(name) in JS-land. See lib/prelude.js
0
 
0
   jsval nsJohnson;    
0
-  JCHECK(JS_GetProperty(context->js, context->global, "Johnson", &nsJohnson));
0
+  JCHECK(JS_GetProperty(context, runtime->global, "Johnson", &nsJohnson));
0
   JROOT(nsJohnson);
0
 
0
-  JCHECK(JS_CallFunctionName(context->js, JSVAL_TO_OBJECT(nsJohnson), "symbolize", 1, &name, retval));
0
+  JCHECK(JS_CallFunctionName(context, JSVAL_TO_OBJECT(nsJohnson), "symbolize", 1, &name, retval));
0
 
0
   JRETURN;
0
 }
0
 
0
-static JSBool convert_regexp_to_js(OurContext* context, VALUE regexp, jsval* retval)
0
+static JSBool convert_regexp_to_js(JohnsonRuntime* runtime, VALUE regexp, jsval* retval)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   VALUE source = rb_funcall(regexp, rb_intern("source"), 0);
0
   int options = NUM2INT(rb_funcall(regexp, rb_intern("options"), 0));
0
 
0
-  JSObject* obj = JS_NewRegExpObject(context->js,
0
+  JSObject* obj = JS_NewRegExpObject(context,
0
         StringValuePtr(source),
0
         (unsigned) StringValueLen(source),
0
         (unsigned) options);
0
@@ -54,8 +57,9 @@ static JSBool convert_regexp_to_js(OurContext* context, VALUE regexp, jsval* ret
0
   }
0
 }
0
 
0
-JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)
0
+JSBool convert_to_js(JohnsonRuntime* runtime, VALUE ruby, jsval* retval)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   switch(TYPE(ruby))
0
   {
0
     case T_NIL:
0
@@ -72,7 +76,7 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)
0
 
0
     case T_STRING:
0
       {
0
-        JSString* str = JS_NewStringCopyN(context->js, StringValuePtr(ruby), (unsigned) StringValueLen(ruby));
0
+        JSString* str = JS_NewStringCopyN(context, StringValuePtr(ruby), (unsigned) StringValueLen(ruby));
0
         if (str) {
0
           *retval = STRING_TO_JSVAL(str);
0
           return JS_TRUE;
0
@@ -87,10 +91,10 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)
0
 
0
     case T_FLOAT:
0
     case T_BIGNUM:
0
-      return convert_float_or_bignum_to_js(context, ruby, retval);
0
+      return convert_float_or_bignum_to_js(runtime, ruby, retval);
0
 
0
     case T_SYMBOL:
0
-      return convert_symbol_to_js(context, ruby, retval);
0
+      return convert_symbol_to_js(runtime, ruby, retval);
0
 
0
     case T_CLASS:
0
     case T_ARRAY:
0
@@ -99,17 +103,17 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)
0
     case T_FILE:
0
     case T_STRUCT:
0
     case T_OBJECT:
0
-      return make_js_land_proxy(context, ruby, retval);
0
+      return make_js_land_proxy(runtime, ruby, retval);
0
       
0
     case T_REGEXP:
0
-      return convert_regexp_to_js(context, ruby, retval);
0
+      return convert_regexp_to_js(runtime, ruby, retval);
0
 
0
     case T_DATA: // HEY! keep T_DATA last for fall-through
0
       if (ruby_value_is_proxy(ruby))
0
-        return unwrap_ruby_land_proxy(context, ruby, retval);
0
+        return unwrap_ruby_land_proxy(runtime, ruby, retval);
0
 
0
       // If we can't identify the object, just wrap it
0
-      return make_js_land_proxy(context, ruby, retval);
0
+      return make_js_land_proxy(runtime, ruby, retval);
0
     
0
     default:
0
       Johnson_Error_raise("unknown ruby type in switch");
0
@@ -119,8 +123,9 @@ JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval)
0
   return JS_TRUE;
0
 }
0
 
0
-VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str)
0
+VALUE convert_js_string_to_ruby(JohnsonRuntime* runtime, JSString* str)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   PREPARE_RUBY_JROOTS(context, 1);
0
   JROOT(str);
0
   char* bytes = JS_GetStringBytes(str);
0
@@ -128,55 +133,60 @@ VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str)
0
   JRETURN_RUBY(rb_str_new(bytes, (signed)JS_GetStringLength(str)));
0
 }
0
 
0
-static VALUE convert_regexp_to_ruby(OurContext* context, jsval regexp)
0
+static VALUE convert_regexp_to_ruby(JohnsonRuntime* runtime, jsval regexp)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   PREPARE_RUBY_JROOTS(context, 1);
0
   JROOT(regexp);
0
-  JSRegExp* re = (JSRegExp*)JS_GetPrivate(context->js, JSVAL_TO_OBJECT(regexp));
0
+  JSRegExp* re = (JSRegExp*)JS_GetPrivate(context, JSVAL_TO_OBJECT(regexp));
0
 
0
   JRETURN_RUBY(CALL_RUBY_WRAPPER(rb_funcall_2, rb_cRegexp, rb_intern("new"), 2,
0
-    convert_jsstring_to_ruby(context, re->source),
0
+    convert_js_string_to_ruby(runtime, re->source),
0
     INT2NUM(re->flags)));
0
 }
0
 
0
-static bool js_value_is_regexp(OurContext* context, jsval maybe_regexp)
0
+static bool js_value_is_regexp(JohnsonRuntime* runtime, jsval maybe_regexp)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   PREPARE_RUBY_JROOTS(context, 1);
0
   JROOT(maybe_regexp);
0
-  JSBool result = JS_InstanceOf(context->js, JSVAL_TO_OBJECT(maybe_regexp), &js_RegExpClass, NULL);
0
+  JSBool result = JS_InstanceOf(context, JSVAL_TO_OBJECT(maybe_regexp), &js_RegExpClass, NULL);
0
   JRETURN_RUBY(result ? true : false);
0
 }
0
 
0
-static bool js_value_is_symbol(OurContext* context, jsval maybe_symbol)
0
+static bool js_value_is_symbol(JohnsonRuntime* runtime, jsval maybe_symbol)
0
 {
0
   jsval nsJohnson, cSymbol;
0
+  JSContext * context = johnson_get_current_context(runtime);
0
 
0
   PREPARE_RUBY_JROOTS(context, 3);
0
   JROOT(maybe_symbol);
0
 
0
-  JCHECK(JS_GetProperty(context->js, context->global, "Johnson", &nsJohnson));
0
+  JCHECK(JS_GetProperty(context, runtime->global, "Johnson", &nsJohnson));
0
   if (!JSVAL_IS_OBJECT(nsJohnson))
0
     JERROR("Unable to retrieve Johnson from JSLand");
0
   JROOT(nsJohnson);
0
 
0
-  JCHECK(JS_GetProperty(context->js, JSVAL_TO_OBJECT(nsJohnson), "Symbol", &cSymbol));
0
+  JCHECK(JS_GetProperty(context, JSVAL_TO_OBJECT(nsJohnson), "Symbol", &cSymbol));
0
   if (!JSVAL_IS_OBJECT(cSymbol))
0
     JERROR("Unable to retrieve Johnson.Symbol from JSLand");
0
   JROOT(cSymbol);
0
 
0
   JSBool is_a_symbol;
0
-  JCHECK(JS_HasInstance(context->js, JSVAL_TO_OBJECT(cSymbol), maybe_symbol, &is_a_symbol));
0
+  JCHECK(JS_HasInstance(context, JSVAL_TO_OBJECT(cSymbol), maybe_symbol, &is_a_symbol));
0
 
0
   JRETURN_RUBY(is_a_symbol != JS_FALSE);
0
 }
0
 
0
-VALUE convert_to_ruby(OurContext* context, jsval js)
0
+VALUE convert_to_ruby(JohnsonRuntime* runtime, jsval js)
0
 {
0
   if (JSVAL_NULL == js) return Qnil;
0
 
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+
0
   PREPARE_RUBY_JROOTS(context, 1);
0
   
0
-  switch (JS_TypeOfValue(context->js, js))
0
+  switch (JS_TypeOfValue(context, js))
0
   {
0
     case JSTYPE_VOID:
0
       JRETURN_RUBY(Qnil);
0
@@ -185,27 +195,27 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
0
     case JSTYPE_OBJECT:
0
       JROOT(js);
0
 
0
-      if (OBJECT_TO_JSVAL(context->global) == js)
0
+      if (OBJECT_TO_JSVAL(runtime->global) == js)
0
         // global gets special treatment, since the Prelude might not be loaded
0
-        JRETURN_RUBY(make_ruby_land_proxy(context, js));
0
+        JRETURN_RUBY(make_ruby_land_proxy(runtime, js));
0
       
0
       // this conditional requires the Prelude
0
-      if (js_value_is_symbol(context, js))
0
-        JRETURN_RUBY(ID2SYM(rb_intern(JS_GetStringBytes(JS_ValueToString(context->js, js)))));
0
+      if (js_value_is_symbol(runtime, js))
0
+        JRETURN_RUBY(ID2SYM(rb_intern(JS_GetStringBytes(JS_ValueToString(context, js)))));
0
     
0
-      if (js_value_is_proxy(context, js))
0
-        JRETURN_RUBY(unwrap_js_land_proxy(context, js));
0
+      if (js_value_is_proxy(runtime, js))
0
+        JRETURN_RUBY(unwrap_js_land_proxy(runtime, js));
0
 
0
-      if (js_value_is_regexp(context, js))
0
-        JRETURN_RUBY(convert_regexp_to_ruby(context, js));
0
+      if (js_value_is_regexp(runtime, js))
0
+        JRETURN_RUBY(convert_regexp_to_ruby(runtime, js));
0
     
0
-      JRETURN_RUBY(make_ruby_land_proxy(context, js));
0
+      JRETURN_RUBY(make_ruby_land_proxy(runtime, js));
0
         
0
     case JSTYPE_BOOLEAN:
0
       JRETURN_RUBY(JSVAL_TRUE == js ? Qtrue : Qfalse);
0
       
0
     case JSTYPE_STRING:
0
-      JRETURN_RUBY(convert_jsstring_to_ruby(context, JSVAL_TO_STRING(js)));
0
+      JRETURN_RUBY(convert_js_string_to_ruby(runtime, JSVAL_TO_STRING(js)));
0
       
0
     case JSTYPE_NUMBER:
0
       if (JSVAL_IS_INT(js)) JRETURN_RUBY(INT2FIX(JSVAL_TO_INT(js)));
0
@@ -218,32 +228,35 @@ VALUE convert_to_ruby(OurContext* context, jsval js)
0
   JRETURN_RUBY(Qnil);
0
 }
0
 
0
-NORETURN(void) raise_js_error_in_ruby(OurContext* context)
0
+NORETURN(void) raise_js_error_in_ruby(JohnsonRuntime* runtime)
0
 {
0
-  if (JS_IsExceptionPending(context->js))
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+  JohnsonContext * johnson_context = OUR_CONTEXT(context);
0
+  if (JS_IsExceptionPending(context))
0
   {
0
-    assert(JS_GetPendingException(context->js, &(context->ex)));
0
-    JS_AddNamedRoot(context->js, &(context->ex), "raise_js_error_in_ruby");
0
-    JS_ClearPendingException(context->js);
0
-    JS_RemoveRoot(context->js, &(context->ex));
0
+    assert(JS_GetPendingException(context, &(johnson_context->ex)));
0
+    JS_AddNamedRoot(context, &(johnson_context->ex), "raise_js_error_in_ruby");
0
+    JS_ClearPendingException(context);
0
+    JS_RemoveRoot(context, &(johnson_context->ex));
0
   }
0
 
0
-  VALUE ruby_context = (VALUE)JS_GetContextPrivate(context->js);
0
-  if (context->ex)
0
+  VALUE ruby_context = (VALUE)JS_GetContextPrivate(context);
0
+  if (johnson_context->ex)
0
     rb_funcall(ruby_context, rb_intern("handle_js_exception"),
0
-      1, convert_to_ruby(context, context->ex));
0
+      1, convert_to_ruby(runtime, johnson_context->ex));
0
 
0
-  if (!context->msg)
0
+  if (!johnson_context->msg)
0
     Johnson_Error_raise("Unknown JavaScript Error");
0
 
0
-  Johnson_Error_raise(context->msg);
0
+  Johnson_Error_raise(johnson_context->msg);
0
 }
0
 
0
 #define TAG_RAISE 0x6
0
 #define TAG_THROW 0x7
0
 
0
-JSBool report_ruby_error_in_js(OurContext* context, int state, VALUE old_errinfo)
0
+JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   assert(state);
0
   switch (state)
0
   {
0
@@ -252,9 +265,9 @@ JSBool report_ruby_error_in_js(OurContext* context, int state, VALUE old_errinfo
0
         VALUE local_error = ruby_errinfo;
0
         jsval js_err;
0
         ruby_errinfo = old_errinfo;
0
-        if (!convert_to_js(context, local_error, &js_err))
0
+        if (!convert_to_js(runtime, local_error, &js_err))
0
           return JS_FALSE;
0
-        JS_SetPendingException(context->js, js_err);
0
+        JS_SetPendingException(context, js_err);
0
         return JS_FALSE;
0
       }
0
 
0
@@ -263,9 +276,9 @@ JSBool report_ruby_error_in_js(OurContext* context, int state, VALUE old_errinfo
0
 
0
     default:
0
       {
0
-        JSString* str = JS_NewStringCopyZ(context->js, "Unexpected longjmp from ruby!");
0
+        JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!");
0
         if (str)
0
-          JS_SetPendingException(context->js, STRING_TO_JSVAL(str));
0
+          JS_SetPendingException(context, STRING_TO_JSVAL(str));
0
         return JS_FALSE;
0
       }
0
   }
...
3
4
5
 
6
7
8
 
 
9
10
11
12
 
 
 
13
14
15
 
 
16
17
...
3
4
5
6
7
 
 
8
9
10
 
 
 
11
12
13
14
 
 
15
16
17
18
0
@@ -3,15 +3,16 @@
0
 
0
 #include "spidermonkey.h"
0
 #include "context.h"
0
+#include "runtime.h"
0
 
0
-DECLARE_RUBY_WRAPPER(convert_to_ruby, OurContext* context; jsval js_value)
0
-#define CONVERT_TO_RUBY(context, js) CALL_RUBY_WRAPPER(convert_to_ruby, context, js)
0
+DECLARE_RUBY_WRAPPER(convert_to_ruby, JohnsonRuntime* runtime; jsval js_value)
0
+#define CONVERT_TO_RUBY(runtime, js) CALL_RUBY_WRAPPER(convert_to_ruby, runtime, js)
0
 
0
-JSBool convert_to_js(OurContext* context, VALUE ruby, jsval* retval);
0
-VALUE convert_to_ruby(OurContext* context, jsval js);
0
-VALUE convert_jsstring_to_ruby(OurContext* context, JSString* str);
0
+JSBool convert_to_js(JohnsonRuntime* runtime, VALUE ruby, jsval* retval);
0
+VALUE convert_to_ruby(JohnsonRuntime* runtime, jsval js);
0
+VALUE convert_js_string_to_ruby(JohnsonRuntime* runtime, JSString* str);
0
 
0
-NORETURN(void raise_js_error_in_ruby(OurContext* context));
0
-JSBool report_ruby_error_in_js(OurContext* context, int state, VALUE old_errinfo);
0
+NORETURN(void raise_js_error_in_ruby(JohnsonRuntime* runtime));
0
+JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo);
0
 
0
 #endif
...
8
9
10
11
 
12
13
14
...
40
41
42
43
 
44
45
46
...
82
83
84
85
 
86
87
88
...
93
94
95
96
 
97
98
99
...
8
9
10
 
11
12
13
14
...
40
41
42
 
43
44
45
46
...
82
83
84
 
85
86
87
88
...
93
94
95
 
96
97
98
99
0
@@ -8,7 +8,7 @@ static JSTrapStatus interrupt_handler(JSContext *js, JSScript *UNUSED(script),
0
 {
0
   VALUE self = (VALUE)rb;
0
   VALUE rb_bytecode = jsop_to_symbol(*pc);
0
-  VALUE rb_rval = convert_to_ruby(OUR_CONTEXT(js), *rval);
0
+  VALUE rb_rval = convert_to_ruby(OUR_RUNTIME(js), *rval);
0
   return NUM2INT(rb_funcall(self, rb_intern("interrupt_handler"), 2, rb_bytecode, rb_rval));
0
 }
0
 
0
@@ -40,7 +40,7 @@ static JSTrapStatus debugger_handler(JSContext *js, JSScript *UNUSED(script),
0
 {
0
   VALUE self = (VALUE)rb;
0
   VALUE rb_bytecode = jsop_to_symbol(*pc);
0
-  VALUE rb_rval = convert_to_ruby(OUR_CONTEXT(js), *rval);
0
+  VALUE rb_rval = convert_to_ruby(OUR_RUNTIME(js), *rval);
0
   return NUM2INT(rb_funcall(self, rb_intern("debugger_handler"), 2, rb_bytecode, rb_rval));
0
 }
0
 
0
@@ -82,7 +82,7 @@ static void object_hook(JSContext *js, JSObject *obj, JSBool isNew, void *rb)
0
 {
0
   VALUE self = (VALUE)rb;
0
 
0
-  VALUE rb_obj = convert_to_ruby(OUR_CONTEXT(js), OBJECT_TO_JSVAL(obj));
0
+  VALUE rb_obj = convert_to_ruby(OUR_RUNTIME(js), OBJECT_TO_JSVAL(obj));
0
   VALUE rb_is_new = isNew ? Qtrue : Qfalse;
0
 
0
   rb_funcall(self, rb_intern("object_hook"), 2, rb_obj, rb_is_new);
0
@@ -93,7 +93,7 @@ static JSTrapStatus throw_hook(JSContext *js, JSScript *UNUSED(script),
0
 {
0
   VALUE self = (VALUE)rb;
0
   VALUE rb_bytecode = jsop_to_symbol(*pc);
0
-  VALUE rb_rval = convert_to_ruby(OUR_CONTEXT(js), *rval);
0
+  VALUE rb_rval = convert_to_ruby(OUR_RUNTIME(js), *rval);
0
   return NUM2INT(rb_funcall(self, rb_intern("throw_hook"), 2, rb_bytecode, rb_rval));
0
 }
0
 
...
12
13
14
15
 
16
17
 
18
19
20
 
 
21
22
23
...
12
13
14
 
15
16
 
17
18
19
 
20
21
22
23
24
0
@@ -12,12 +12,13 @@ define_property(JSContext *js_context, JSObject* UNUSED(obj), uintN argc, jsval
0
   return JS_DefineProperty(js_context, JSVAL_TO_OBJECT(argv[0]), name, argc > 2 ? argv[2] : JSVAL_VOID, NULL, NULL, flags);
0
 }
0
 
0
-VALUE init_spidermonkey_extensions(OurContext* context, VALUE self)
0
+VALUE init_spidermonkey_extensions(JohnsonContext* context, VALUE self)
0
 {
0
-  PREPARE_RUBY_JROOTS(context, 1);
0
+  PREPARE_RUBY_JROOTS(context->js, 1);
0
   
0
   jsval Object;
0
-  JCHECK(JS_GetProperty(context->js, context->global, "Object", &Object));
0
+  JSObject * global = JS_GetGlobalObject(context->js);
0
+  JCHECK(JS_GetProperty(context->js, global, "Object", &Object));
0
   JROOT(Object);
0
 
0
   JCHECK(JS_DefineFunction(context->js, JSVAL_TO_OBJECT(Object),
...
5
6
7
8
 
 
 
9
10
...
5
6
7
 
8
9
10
11
12
0
@@ -5,6 +5,8 @@
0
 #include "context.h"
0
 #include "conversions.h"
0
 
0
-VALUE init_spidermonkey_extensions(OurContext* context, VALUE self);
0
+// A context is passed here because there might not be a current context
0
+// for the runtime when the function is called.
0
+VALUE init_spidermonkey_extensions(JohnsonContext* context, VALUE self);
0
 
0
 #endif
...
34
35
36
37
38
39
40
41
42
43
44
45
46
 
...
34
35
36
 
 
 
 
 
37
38
39
 
40
41
0
@@ -34,12 +34,7 @@ static JSClass OurGlobalClass = {
0
   JSCLASS_NO_OPTIONAL_MEMBERS
0
 };
0
 
0
-JSObject* create_global_object(OurContext* context)
0
-{
0
-  return JS_NewObject(context->js, &OurGlobalClass, NULL, NULL);
0
-}
0
-
0
 JSObject* johnson_create_global_object(JSContext* context)
0
 {
0
   return JS_NewObject(context, &OurGlobalClass, NULL, NULL);
0
-}
0
\ No newline at end of file
0
+}
...
5
6
7
8
9
10
11
12
...
5
6
7
 
 
8
9
10
0
@@ -5,8 +5,6 @@
0
 #include "context.h"
0
 #include "runtime.h"
0
 
0
-JSObject* create_global_object(OurContext* context); // FIXME: remove or rename
0
-
0
 // NOTE: one of the FEW places a context should be passed around
0
 JSObject* johnson_create_global_object(JSContext* context);
0
 
...
8
9
10
11
 
12
13
 
14
15
16
 
 
 
 
 
 
 
 
 
 
17
18
19
20
 
21
22
 
23
24
25
...
44
45
46
47
 
48
49
50
...
59
60
61
62
 
63
64
65
...
72
73
74
75
 
76
77
78
...
85
86
87
88
 
89
90
91
...
96
97
98
99
 
100
101
102
...
113
114
115
116
 
117
118
119
...
145
146
147
148
149
 
 
150
151
152
...
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
...
54
55
56
 
57
58
59
60
...
69
70
71
 
72
73
74
75
...
82
83
84
 
85
86
87
88
...
95
96
97
 
98
99
100
101
...
106
107
108
 
109
110
111
112
...
123
124
125
 
126
127
128
129
...
155
156
157
 
 
158
159
160
161
162
0
@@ -8,18 +8,28 @@
0
 
0
 #define OUR_CONTEXT(js_context) \
0
   ({ \
0
-    OurContext* _context; \
0
+    JohnsonContext* _context; \
0
     const VALUE _ruby_context = (VALUE)JS_GetContextPrivate(js_context); \
0
-    Data_Get_Struct(_ruby_context, OurContext, _context); \
0
+    Data_Get_Struct(_ruby_context, JohnsonContext, _context); \
0
     _context; \
0
   })
0
 
0
+#define OUR_RUNTIME(js_context) \
0
+  ({ \
0
+    JohnsonRuntime* _johnson_runtime; \
0
+    JSRuntime * _js_runtime = JS_GetRuntime(js_context);\
0
+    const VALUE _ruby_runtime = (VALUE)JS_GetRuntimePrivate(_js_runtime); \
0
+    Data_Get_Struct(_ruby_runtime, JohnsonRuntime, _johnson_runtime); \
0
+    _johnson_runtime; \
0
+   })
0
+    
0
+
0
 #define _PREPARE_JROOTS(rb, context, cleancount) \
0
   const bool _jroot_ruby = (rb); \
0
   const int _jroot_cleans = (cleancount); \
0
-  void (*_jroot_cleanup[_jroot_cleans])(OurContext*, void*); \
0
+  void (*_jroot_cleanup[_jroot_cleans])(JSContext*, void*); \
0
   void* _jroot_cleanup_data[_jroot_cleans]; \
0
-  OurContext* const _jroot_context = (context); \
0
+  JSContext* const _jroot_context = (context); \
0
   int _jroot_cleanidx = 0;
0
 
0
 #define PREPARE_JROOTS(context, cleancount) \
0
@@ -44,7 +54,7 @@
0
     void* const _root = (ptr); \
0
     if (*_name == '\0') \
0
       snprintf(_name, _JROOT_NAMESIZE, "%s[%d]:%s: %s", __FILE__, __LINE__, __func__, (name)); \
0
-    JCHECK(JS_AddNamedRoot(_jroot_context->js, _root, _name)); \
0
+    JCHECK(JS_AddNamedRoot(_jroot_context, _root, _name)); \
0
     JCLEANUP(_JROOT_ROOT, _root); \
0
   } while(0)
0
 
0
@@ -59,7 +69,7 @@
0
     for (_jroot_i = _jroot_cleanidx - 1; _jroot_i >= 0; _jroot_i--) \
0
       if (_jroot_cleanup[_jroot_i] == _JROOT_ROOT && _jroot_cleanup_data[_jroot_i] == _jroot_match) \
0
       { \
0
-        JS_RemoveRoot(_jroot_context->js, _jroot_cleanup_data[_jroot_i]); \
0
+        JS_RemoveRoot(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
0
         if (_jroot_i == _jroot_cleanidx - 1) _jroot_cleanidx--; \
0
         _jroot_cleanup[_jroot_i] = NULL; \
0
       } \
0
@@ -72,7 +82,7 @@
0
     for (_jroot_i = _jroot_cleanidx - 1; _jroot_i >= 0; _jroot_i--) \
0
     { \
0
       if (_jroot_cleanup[_jroot_i] == _JROOT_ROOT) \
0
-        JS_RemoveRoot(_jroot_context->js, _jroot_cleanup_data[_jroot_i]); \
0
+        JS_RemoveRoot(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
0
       else if (_jroot_cleanup[_jroot_i]) \
0
         (_jroot_cleanup[_jroot_i])(_jroot_context, _jroot_cleanup_data[_jroot_i]); \
0
     } \
0
@@ -85,7 +95,7 @@
0
     if (!(cond)) \
0
     { \
0
       REMOVE_JROOTS; \
0
-      raise_js_error_in_ruby(_jroot_context); \
0
+      raise_js_error_in_ruby(OUR_RUNTIME(_jroot_context)); \
0
     } \
0
   } while (0)
0
 
0
@@ -96,7 +106,7 @@
0
     { \
0
       REMOVE_JROOTS; \
0
       if (_jroot_ruby) \
0
-        raise_js_error_in_ruby(_jroot_context); \
0
+        raise_js_error_in_ruby(OUR_RUNTIME(_jroot_context)); \
0
       else \
0
         return JS_FALSE; \
0
     } \
0
@@ -113,7 +123,7 @@
0
       if (_jroot_ruby) \
0
         rb_jump_tag(_state); \
0
       else \
0
-        return report_ruby_error_in_js(_jroot_context, _state, _old_errinfo); \
0
+        return report_ruby_error_in_js(OUR_RUNTIME(_jroot_context), _state, _old_errinfo); \
0
     } \
0
     _result; \
0
   })
0
@@ -145,8 +155,8 @@
0
       Johnson_Error_raise(_jroot_msg); \
0
     else \
0
     { \
0
-      JSString* _jroot_err_str = JS_NewStringCopyZ(_jroot_context->js, _jroot_msg); \
0
-      if (_jroot_err_str) JS_SetPendingException(_jroot_context->js, STRING_TO_JSVAL(_jroot_err_str)); \
0
+      JSString* _jroot_err_str = JS_NewStringCopyZ(_jroot_context, _jroot_msg); \
0
+      if (_jroot_err_str) JS_SetPendingException(_jroot_context, STRING_TO_JSVAL(_jroot_err_str)); \
0
       return JS_FALSE; \
0
     } \
0
   } while(0)
...
58
59
60
61
 
62
63
64
...
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
...
163
164
165
166
167
 
 
168
169
170
...
179
180
181
182
183
 
 
 
184
185
186
...
193
194
195
196
197
 
 
 
198
199
 
 
 
 
200
201
202
...
209
210
211
212
 
213
214
215
...
221
222
223
224
 
225
226
227
...
230
231
232
233
 
234
235
236
...
239
240
241
242
 
243
244
245
246
247
248
249
 
250
251
252
...
254
255
256
257
 
258
259
260
...
262
263
264
265
 
266
267
268
...
273
274
275
276
 
277
278
279
...
284
285
286
287
 
288
289
290
...
296
297
298
299
300
 
 
 
 
 
 
301
302
 
303
304
305
...
312
313
314
315
 
316
317
 
318
319
320
321
322
323
324
 
 
325
326
327
328
329
330
331
 
 
332
333
334
335
336
337
 
 
338
339
340
341
342
343
 
344
345
346
347
348
349
350
 
351
352
353
354
 
355
356
357
...
362
363
364
365
366
 
 
 
367
368
 
 
369
370
 
 
 
371
372
373
374
375
 
376
377
 
378
379
380
...
383
384
385
386
387
 
 
388
389
 
390
391
392
...
406
407
408
409
410
 
 
 
 
 
 
411
412
 
413
414
415
416
 
417
418
419
...
421
422
423
424
425
 
 
 
426
427
 
 
 
 
428
429
430
431
 
432
433
434
...
436
437
438
439
440
 
 
 
 
 
 
441
442
 
443
444
445
...
450
451
452
453
 
454
455
 
456
457
458
...
462
463
464
465
466
 
 
 
467
468
 
 
 
 
469
470
471
...
473
474
475
476
 
477
478
 
479
480
481
482
483
 
484
485
 
 
 
486
487
488
489
490
491
492
 
493
494
495
 
496
497
498
 
 
499
500
501
...
506
507
508
509
510
 
 
 
 
 
 
511
512
513
514
515
516
 
517
518
519
 
520
521
522
523
 
524
525
 
 
526
527
528
529
 
530
531
532
...
548
549
550
551
 
552
553
554
 
555
556
 
557
558
559
 
 
560
561
562
563
564
 
565
566
567
 
568
569
570
 
571
572
573
...
58
59
60
 
61
62
63
64
...
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
...
163
164
165
 
 
166
167
168
169
170
...
179
180
181
 
 
182
183
184
185
186
187
...
194
195
196
 
 
197
198
199
200
 
201
202
203
204
205
206
207
...
214
215
216
 
217
218
219
220
...
226
227
228
 
229
230
231
232
...
235
236
237
 
238
239
240
241
...
244
245
246
 
247
248
249
250
251
252
253
 
254
255
256
257
...
259
260
261
 
262
263
264
265
...
267
268
269
 
270
271
272
273
...
278
279
280
 
281
282
283
284
...
289
290
291
 
292
293
294
295
...
301
302
303
 
 
304
305
306
307
308
309
310
 
311
312
313
314
...
321
322
323
 
324
325
 
326
327
328
329
330
331
 
 
332
333
334
335
336
337
338
 
 
339
340
341
342
343
344
 
 
345
346
347
348
349
350
351
 
352
353
354
355
356
357
358
 
359
360
361
362
 
363
364
365
366
...
371
372
373
 
 
374
375
376
377
 
378
379
380
 
381
382
383
384
385
386
387
 
388
389
 
390
391
392
393
...
396
397
398
 
 
399
400
401
 
402
403
404
405
...
419
420
421
 
 
422
423
424
425
426
427
428
 
429
430
431
432
 
433
434
435
436
...
438
439
440
 
 
441
442
443
444
 
445
446
447
448
449
450
451
 
452
453
454
455
...
457
458
459
 
 
460
461
462
463
464
465
466
 
467
468
469
470
...
475
476
477
 
478
479
 
480
481
482
483
...
487
488
489
 
 
490
491
492
493
 
494
495
496
497
498
499
500
...
502
503
504
 
505
506
 
507
508
509
510
511
 
512
513
 
514
515
516
517
518
519
520
521
522
 
523
524
525
526
527
528
 
 
529
530
531
532
533
...
538
539
540
 
 
541
542
543
544
545
546
547
548
549
550
551
 
552
553
554
 
555
556
557
558
 
559
560
 
561
562
563
564
565
 
566
567
568
569
...
585
586
587
 
588
589
590
 
591
592
 
593
594
 
 
595
596
597
598
599
600
 
601
602
603
 
604
605
606
 
607
608
609
610
0
@@ -58,7 +58,7 @@ static VALUE call_ruby_from_js_invoke(VALUE args)
0
   return rb_apply(self, SYM2ID(id), args);
0
 }
0
 
0
-JSBool call_ruby_from_js_va(OurContext* context, VALUE* result, VALUE self, ID id, int argc, va_list va)
0
+JSBool call_ruby_from_js_va(JohnsonRuntime* runtime, VALUE* result, VALUE self, ID id, int argc, va_list va)
0
 {
0
   VALUE old_errinfo = ruby_errinfo;
0
   VALUE args = rb_ary_new2(argc + 2);
0
@@ -74,27 +74,27 @@ JSBool call_ruby_from_js_va(OurContext* context, VALUE* result, VALUE self, ID i
0
   *result = rb_protect(call_ruby_from_js_invoke, args, &state);
0
 
0
   if (state)
0
-    return report_ruby_error_in_js(context, state, old_errinfo);
0
+    return report_ruby_error_in_js(runtime, state, old_errinfo);
0
 
0
   return JS_TRUE;
0
 }
0
 
0
-JSBool call_ruby_from_js(OurContext* context, jsval* retval, VALUE self, ID id, int argc, ...)
0
+JSBool call_ruby_from_js(JohnsonRuntime* runtime, jsval* retval, VALUE self, ID id, int argc, ...)
0
 {
0
   VALUE result;
0
   va_list va;
0
   va_start(va, argc);
0
-  JSBool okay = call_ruby_from_js_va(context, &result, self, id, argc, va);
0
+  JSBool okay = call_ruby_from_js_va(runtime, &result, self, id, argc, va);
0
   va_end(va);
0
   if (!okay) return JS_FALSE;
0
-  return retval ? convert_to_js(context, result, retval) : JS_TRUE;
0
+  return retval ? convert_to_js(runtime, result, retval) : JS_TRUE;
0
 }
0
 
0
-JSBool call_ruby_from_js2(OurContext* context, VALUE* retval, VALUE self, ID id, int argc, ...)
0
+JSBool call_ruby_from_js2(JohnsonRuntime* runtime, VALUE* retval, VALUE self, ID id, int argc, ...)
0
 {
0
   va_list va;
0
   va_start(va, argc);
0
-  JSBool okay = call_ruby_from_js_va(context, retval, self, id, argc, va);
0
+  JSBool okay = call_ruby_from_js_va(runtime, retval, self, id, argc, va);
0
   va_end(va);
0
   return okay;
0
 }
0
@@ -163,8 +163,8 @@ static bool respond_to_p(JSContext* js_context, JSObject* obj, char* name)
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
 
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
   VALUE self = (VALUE)JS_GetInstancePrivate(
0
     context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
0
@@ -179,8 +179,9 @@ static bool respond_to_p(JSContext* js_context, JSObject* obj, char* name)
0
     || has_key_p(self, name);
0
 }
0
 
0
-static jsval evaluate_js_property_expression(OurContext * context, const char * property, jsval* retval) {
0
-  return JS_EvaluateScript(context->js, context->global,
0
+static jsval evaluate_js_property_expression(JohnsonRuntime * runtime, const char * property, jsval* retval) {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+  return JS_EvaluateScript(context, runtime->global,
0
       property, strlen(property), "johnson:evaluate_js_property_expression", 1,
0
       retval);
0
 }
0
@@ -193,10 +194,14 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   // get our struct, which is embedded in ruby_context
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
-  PREPARE_JROOTS(context, 1);
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
+
0
+  PREPARE_JROOTS(js_context, 1);
0
   JROOT(id);
0
     
0
   // get the Ruby object that backs this proxy
0
@@ -209,7 +214,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   {
0
     if (indexable_p(self)) {
0
       VALUE idx = INT2FIX(JSVAL_TO_INT(id));
0
-      JCHECK(call_ruby_from_js(context, retval, self, rb_intern("[]"), 1, idx));
0
+      JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, idx));
0
     }
0
     
0
     JRETURN;
0
@@ -221,7 +226,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   // FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable
0
   
0
   if (!strcasecmp("__iterator__", name)) {
0
-    JCHECK(evaluate_js_property_expression(context, "Johnson.Generator.create", retval));
0
+    JCHECK(evaluate_js_property_expression(runtime, "Johnson.Generator.create", retval));
0
   }
0
   
0
   // if the Ruby object has a dynamic js property with a key
0
@@ -230,7 +235,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   else if (autovivified_p(ruby_context, self, name))
0
   {
0
-    JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
+    JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
       rb_intern("autovivified"), 2, self, rb_str_new2(name)));
0
   }
0
 
0
@@ -239,14 +244,14 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   else if (const_p(self, name))
0
   {
0
-    JCHECK(call_ruby_from_js(context, retval, self, rb_intern("const_get"),
0
+    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("const_get"),
0
       1, ID2SYM(ruby_id)));
0
   }  
0
 
0
   // otherwise, if it's a global, return the global
0
   else if (global_p(name))
0
   {
0
-    JCHECK(convert_to_js(context, rb_gv_get(name), retval));
0
+    JCHECK(convert_to_js(runtime, rb_gv_get(name), retval));
0
   }
0
   
0
   // otherwise, if the Ruby object has a an attribute method matching
0
@@ -254,7 +259,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   else if (attribute_p(self, name))
0
   {
0
-    JCHECK(call_ruby_from_js(context, retval, self, ruby_id, 0));
0
+    JCHECK(call_ruby_from_js(runtime, retval, self, ruby_id, 0));
0
   }
0
 
0
   // otherwise, if the Ruby object quacks sorta like a hash (it responds to
0
@@ -262,7 +267,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   else if (has_key_p(self, name))
0
   {
0
-    JCHECK(call_ruby_from_js(context, retval, self, rb_intern("[]"), 1, rb_str_new2(name)));
0
+    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, rb_str_new2(name)));
0
   }
0
   
0
   // otherwise, it's a method being accessed as a property, which means
0
@@ -273,7 +278,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
   
0
   else if (method_p(self, name))
0
   {
0
-    JCHECK(call_ruby_from_js(context, retval, self, rb_intern("method"), 1, rb_str_new2(name)));
0
+    JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("method"), 1, rb_str_new2(name)));
0
   }
0
 
0
   // else it's undefined (JS_VOID) by default
0
@@ -284,7 +289,7 @@ static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
 static JSBool get_and_destroy_resolved_property(
0
   JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
0
 {
0
-  PREPARE_JROOTS(OUR_CONTEXT(js_context), 1);
0
+  PREPARE_JROOTS(js_context, 1);
0
   JROOT(id);
0
   char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
0
   JCHECK(JS_DeleteProperty(js_context, obj, name));
0
@@ -296,10 +301,14 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
+
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
 
0
-  PREPARE_JROOTS(context, 2);
0
+  PREPARE_JROOTS(js_context, 2);
0
   JROOT(id);
0
   JROOT_PTR(value);
0
     
0
@@ -312,46 +321,46 @@ static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
0
     if (indexable_p(self))
0
     {
0
       VALUE idx = INT2FIX(JSVAL_TO_INT(id));
0
-      VALUE val = CONVERT_TO_RUBY(context, *value);
0
+      VALUE val = CONVERT_TO_RUBY(runtime, *value);
0
 
0
-      JCHECK(call_ruby_from_js(context, NULL, self, rb_intern("[]="), 2, idx, val));
0
+      JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, idx, val));
0
     }
0
 
0
     JRETURN;
0
   }
0
   
0
-  VALUE ruby_key = CONVERT_TO_RUBY(context, id);
0
-  VALUE ruby_value = CONVERT_TO_RUBY(context, *value);
0
+  VALUE ruby_key = CONVERT_TO_RUBY(runtime, id);
0
+  VALUE ruby_value = CONVERT_TO_RUBY(runtime, *value);
0
 
0
   VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("="));
0
   VALUE setter_id = rb_intern(StringValueCStr(setter));
0
   
0
   VALUE settable_p, indexable_p;
0
-  JCHECK(call_ruby_from_js2(context, &settable_p, self, rb_intern("respond_to?"), 1, ID2SYM(setter_id)));
0
-  JCHECK(call_ruby_from_js2(context, &indexable_p, self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]="))));
0
+  JCHECK(call_ruby_from_js2(runtime, &settable_p, self, rb_intern("respond_to?"), 1, ID2SYM(setter_id)));
0
+  JCHECK(call_ruby_from_js2(runtime, &indexable_p, self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]="))));
0
   
0
   if (settable_p)
0
   {
0
     VALUE method, arity;
0
-    JCHECK(call_ruby_from_js2(context, &method, self, rb_intern("method"), 1, ID2SYM(setter_id)));
0
-    JCHECK(call_ruby_from_js2(context, &arity, method, rb_intern("arity"), 0));
0
+    JCHECK(call_ruby_from_js2(runtime, &method, self, rb_intern("method"), 1, ID2SYM(setter_id)));
0
+    JCHECK(call_ruby_from_js2(runtime, &arity, method, rb_intern("arity"), 0));
0
 
0
     // if the Ruby object has a 1-arity method named "property=",
0
     // call it with the converted value
0
     
0
     if (NUM2INT(arity) == 1)
0
-      JCHECK(call_ruby_from_js(context, NULL, self, setter_id, 1, ruby_value));
0
+      JCHECK(call_ruby_from_js(runtime, NULL, self, setter_id, 1, ruby_value));
0
   }
0
   else if(indexable_p)
0
   {
0
     // otherwise, if the Ruby object quacks sorta like a hash for assignment
0
     // (it responds to "[]="), assign it by key
0
     
0
-    JCHECK(call_ruby_from_js(context, NULL, self, rb_intern("[]="), 2, ruby_key, ruby_value));
0
+    JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, ruby_key, ruby_value));
0
   }
0
   else
0
   {
0
-    JCHECK(call_ruby_from_js(context, NULL, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"), 
0
+    JCHECK(call_ruby_from_js(runtime, NULL, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"), 
0
       3, self, ruby_key, ruby_value));
0
   }
0
 
0
@@ -362,19 +371,23 @@ static JSBool construct(JSContext* js_context, JSObject* UNUSED(obj), uintN argc
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
-  PREPARE_JROOTS(context, 0);
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
 
0
-  VALUE klass = CONVERT_TO_RUBY(context, JS_ARGV_CALLEE(argv));
0
+  PREPARE_JROOTS(js_context, 0);
0
+
0
+  VALUE klass = CONVERT_TO_RUBY(runtime, JS_ARGV_CALLEE(argv));
0
   VALUE args = rb_ary_new();
0
 
0
   uintN i;
0
   for (i = 0; i < argc; ++i)
0
-    rb_ary_push(args, CONVERT_TO_RUBY(context, argv[i]));
0
+    rb_ary_push(args, CONVERT_TO_RUBY(runtime, argv[i]));
0
     
0
-  JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
+  JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
     rb_intern("send_with_possible_block"), 3, klass, ID2SYM(rb_intern("new")), args));
0
   JRETURN;
0
 }
0
@@ -383,10 +396,10 @@ static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN UNUS
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
-  PREPARE_JROOTS(context, 1);
0
+  PREPARE_JROOTS(js_context, 1);
0
   JROOT(id);
0
   
0
   char* name = JS_GetStringBytes(JS_ValueToString(js_context, id));
0
@@ -406,14 +419,18 @@ static JSBool to_string(JSContext* js_context, JSObject* obj, uintN UNUSED(argc)
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
 
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
+
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
 
0
-  PREPARE_JROOTS(context, 0);
0
+  PREPARE_JROOTS(js_context, 0);
0
 
0
   VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
0
 
0
-  JCHECK(call_ruby_from_js(context, retval, self, rb_intern("to_s"), 0));
0
+  JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("to_s"), 0));
0
   JRETURN;
0
 }
0
 
0
@@ -421,14 +438,18 @@ static JSBool to_array(JSContext* js_context, JSObject* obj, uintN UNUSED(argc),
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
 
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
-  PREPARE_JROOTS(context, 0);
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
+
0
+  PREPARE_JROOTS(js_context, 0);
0
 
0
   VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
0
 
0
-  JCHECK(call_ruby_from_js(context, retval, self, rb_intern("to_a"), 0));
0
+  JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("to_a"), 0));
0
   JRETURN;
0
 }
0
 
0
@@ -436,10 +457,14 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
+
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
 
0
-  PREPARE_JROOTS(context, 0);
0
+  PREPARE_JROOTS(js_context, 0);
0
     
0
   VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
0
   
0
@@ -450,9 +475,9 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j
0
   
0
   // FIXME: this is horrible and lazy, to_a comes from enumerable on proxy (argv[1] is a JSArray)
0
   VALUE args;
0
-  JCHECK(call_ruby_from_js2(context, &args, CONVERT_TO_RUBY(context, argv[1]), rb_intern("to_a"), 0));
0
+  JCHECK(call_ruby_from_js2(runtime, &args, CONVERT_TO_RUBY(runtime, argv[1]), rb_intern("to_a"), 0));
0
 
0
-  JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
+  JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
     rb_intern("send_with_possible_block"), 3, self, ID2SYM(ruby_id), args));
0
 
0
   JRETURN;
0
@@ -462,10 +487,14 @@ static JSBool call(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsv
0
 {
0
   VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
0
   
0
-  OurContext* context;
0
-  Data_Get_Struct(ruby_context, OurContext, context);
0
+  JohnsonContext* context;
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(ruby_context, JohnsonContext, context);
0
 
0
-  PREPARE_JROOTS(context, 0);
0
+  VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+  Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
+
0
+  PREPARE_JROOTS(js_context, 0);
0
   
0
   VALUE self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL);
0
   
0
@@ -473,29 +502,32 @@ static JSBool call(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsv
0
 
0
   uintN i;
0
   for (i = 0; i < argc; ++i)
0
-    rb_ary_push(args, CONVERT_TO_RUBY(context, argv[i]));
0
+    rb_ary_push(args, CONVERT_TO_RUBY(runtime, argv[i]));
0
   
0
-  JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
+  JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(),
0
     rb_intern("send_with_possible_block"), 3, self, ID2SYM(rb_intern("call")), args));
0
   JRETURN;
0
 }
0
 
0
-bool js_value_is_proxy(OurContext* MAYBE_UNUSED(context), jsval maybe_proxy)
0
+bool js_value_is_proxy(JohnsonRuntime* MAYBE_UNUSED(runtime), jsval maybe_proxy)
0
 {
0
-  JSClass* klass = JS_GET_CLASS(context->js, JSVAL_TO_OBJECT(maybe_proxy));  
0
+  JSClass* klass = JS_GET_CLASS(
0
+      johnson_get_current_context(runtime),
0
+      JSVAL_TO_OBJECT(maybe_proxy));  
0
   
0
   return &JSLandProxyClass == klass
0
     || &JSLandClassProxyClass == klass
0
     || &JSLandCallableProxyClass == klass;
0
 }
0
 
0
-VALUE unwrap_js_land_proxy(OurContext* context, jsval proxy)
0
+VALUE unwrap_js_land_proxy(JohnsonRuntime* runtime, jsval proxy)
0
 {
0
   VALUE value;
0
   JSObject *proxy_object = JSVAL_TO_OBJECT(proxy);
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   
0
-  value = (VALUE)JS_GetInstancePrivate(context->js, proxy_object,
0
-          JS_GET_CLASS(context->js, proxy_object), NULL);
0
+  value = (VALUE)JS_GetInstancePrivate(context, proxy_object,
0
+          JS_GET_CLASS(context, proxy_object), NULL);
0
   
0
   return value;
0
 }
0
@@ -506,27 +538,32 @@ static void finalize(JSContext* js_context, JSObject* obj)
0
   
0
   if (ruby_context)
0
   {
0
-    OurContext* context;
0
-    Data_Get_Struct(ruby_context, OurContext, context);
0
+    JohnsonContext* context;
0
+    JohnsonRuntime* runtime;
0
+    Data_Get_Struct(ruby_context, JohnsonContext, context);
0
+
0
+    VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context));
0
+    Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime);
0
     
0
     VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj,
0
             JS_GET_CLASS(context->js, obj), NULL);
0
     
0
     // remove the proxy OID from the id map
0
-    JS_HashTableRemove(context->rbids, (void *)rb_obj_id(self));
0
+    JS_HashTableRemove(runtime->rbids, (void *)rb_obj_id(self));
0
     
0
     // free up the ruby value for GC
0
-    call_ruby_from_js(context, NULL, ruby_context, rb_intern("remove_gcthing"), 1, self);
0
+    call_ruby_from_js(runtime, NULL, ruby_context, rb_intern("remove_gcthing"), 1, self);
0
   }  
0
 }
0
 
0
-JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval)
0
+JSBool make_js_land_proxy(JohnsonRuntime* runtime, VALUE value, jsval* retval)
0
 {
0
-  jsid id = (jsid)JS_HashTableLookup(context->rbids, (void *)rb_obj_id(value));
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+  jsid id = (jsid)JS_HashTableLookup(runtime->rbids, (void *)rb_obj_id(value));
0
   
0
   if (id)
0
   {
0
-    return JS_IdToValue(context->js, id, retval);
0
+    return JS_IdToValue(context, id, retval);
0
   }
0
   else
0
   {
0
@@ -548,26 +585,26 @@ JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval)
0
     if (callable_p)
0
       klass = &JSLandCallableProxyClass;
0
         
0
-    JCHECK((jsobj = JS_NewObject(context->js, klass, NULL, NULL)));
0
+    JCHECK((jsobj = JS_NewObject(context, klass, NULL, NULL)));
0
     JROOT(jsobj);
0
     
0
-    JCHECK(JS_SetPrivate(context->js, jsobj, (void*)value));
0
+    JCHECK(JS_SetPrivate(context, jsobj, (void*)value));
0
 
0
-    JCHECK(JS_DefineFunction(context->js, jsobj, "__noSuchMethod__", method_missing, 2, 0));
0
+    JCHECK(JS_DefineFunction(context, jsobj, "__noSuchMethod__", method_missing, 2, 0));
0
 
0
-    JCHECK(JS_DefineFunction(context->js, jsobj, "toArray", to_array, 0, 0));
0
-    JCHECK(JS_DefineFunction(context->js, jsobj, "toString", to_string, 0, 0));
0
+    JCHECK(JS_DefineFunction(context, jsobj, "toArray", to_array, 0, 0));
0
+    JCHECK(JS_DefineFunction(context, jsobj, "toString", to_string, 0, 0));
0
 
0
     *retval = OBJECT_TO_JSVAL(jsobj);
0
 
0
     jsval newid;
0
-    JCHECK(JS_ValueToId(context->js, *retval, &newid));
0
+    JCHECK(JS_ValueToId(context, *retval, &newid));
0
   
0
     // put the proxy OID in the id map
0
-    JCHECK(JS_HashTableAdd(context->rbids, (void *)rb_obj_id(value), (void *)newid));
0
+    JCHECK(JS_HashTableAdd(runtime->rbids, (void *)rb_obj_id(value), (void *)newid));
0
     
0
     // root the ruby value for GC
0
-    VALUE ruby_context = (VALUE)JS_GetContextPrivate(context->js);
0
+    VALUE ruby_context = (VALUE)JS_GetContextPrivate(context);
0
     rb_funcall(ruby_context, rb_intern("add_gcthing"), 1, value);
0
 
0
     JRETURN;
...
2
3
4
5
 
6
7
8
9
 
 
 
10
11
12
...
2
3
4
 
5
6
 
 
 
7
8
9
10
11
12
0
@@ -2,11 +2,11 @@
0
 #define JOHNSON_SPIDERMONKEY_JS_LAND_PROXY_H
0
 
0
 #include "spidermonkey.h"
0
-#include "context.h"
0
+#include "runtime.h"
0
 
0
-bool js_value_is_proxy(OurContext* context, jsval maybe_proxy);
0
-VALUE unwrap_js_land_proxy(OurContext* context, jsval proxy);
0
-JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval);
0
+bool js_value_is_proxy(JohnsonRuntime* runtime, jsval maybe_proxy);
0
+VALUE unwrap_js_land_proxy(JohnsonRuntime* runtime, jsval proxy);
0
+JSBool make_js_land_proxy(JohnsonRuntime* runtime, VALUE value, jsval* retval);
0
 
0
 #include "node.h"
0
 typedef struct {
...
12
13
14
15
 
 
16
17
18
19
 
20
21
22
23
 
24
25
26
27
 
28
29
30
31
 
32
 
33
34
35
...
43
44
45
46
 
47
48
49
50
 
51
52
53
 
54
55
56
...
65
66
67
68
 
 
69
70
71
...
75
76
77
78
 
79
80
81
82
83
 
84
85
86
87
88
 
89
90
91
...
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
...
137
138
139
140
 
 
141
142
143
 
144
145
146
...
155
156
157
158
 
 
159
160
161
...
170
171
172
173
 
174
175
176
 
177
178
179
...
195
196
197
 
198
199
 
200
201
202
203
204
205
206
 
207
208
 
209
210
211
212
 
213
214
 
215
216
217
...
225
226
227
 
228
229
 
230
231
232
...
236
237
238
239
 
240
241
242
 
243
244
245
246
247
248
249
 
 
250
251
252
253
254
255
 
256
257
258
...
262
263
264
265
 
266
267
268
269
270
271
 
272
273
274
275
276
277
 
278
279
280
281
282
283
 
 
284
285
286
...
303
304
305
 
306
307
 
308
309
310
...
313
314
315
316
 
317
318
319
 
320
321
322
323
324
325
 
326
327
328
329
 
330
331
332
...
334
335
336
337
 
338
339
 
340
341
342
 
343
344
345
346
 
347
348
349
...
359
360
361
 
362
363
 
364
365
366
...
368
369
370
371
 
372
373
374
375
376
 
377
378
379
...
389
390
391
 
392
393
394
395
396
 
397
398
399
...
401
402
403
404
 
405
406
407
408
409
 
410
411
412
413
414
415
 
416
417
418
...
425
426
427
 
428
429
 
430
431
432
433
434
435
436
 
 
437
438
439
...
442
443
444
445
 
 
446
447
448
449
450
 
451
452
453
 
454
455
456
 
457
458
 
459
460
461
...
466
467
468
469
 
470
 
471
472
473
...
479
480
481
482
 
483
484
 
 
485
486
487
...
501
502
503
504
 
505
506
 
507
508
509
 
510
511
512
...
531
532
533
534
 
535
536
537
...
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
...
45
46
47
 
48
49
50
51
 
52
53
54
 
55
56
57
58
...
67
68
69
 
70
71
72
73
74
...
78
79
80
 
81
82
83
84
85
 
86
87
88
89
90
 
91
92
93
94
...
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
...
141
142
143
 
144
145
146
147
 
148
149
150
151
...
160
161
162
 
163
164
165
166
167
...
176
177
178
 
179
180
181
 
182
183
184
185
...
201
202
203
204
205
 
206
207
208
209
210
211
212
 
213
214
 
215
216
217
218
 
219
220
 
221
222
223
224
...
232
233
234
235
236
 
237
238
239
240
...
244
245
246
 
247
248
249
 
250
251
252
253
254
255
 
 
256
257
258
259
260
261
262
 
263
264
265
266
...
270
271
272
 
273
274
275
276
277
278
 
279
280
281
282
283
284
 
285
286
287
288
289
 
 
290
291
292
293
294
...
311
312
313
314
315
 
316
317
318
319
...
322
323
324
 
325
326
327
 
328
329
330
331
332
333
 
334
335
336
337
 
338
339
340
341
...
343
344
345
 
346
347
 
348
349
350
 
351
352
353
354
 
355
356
357
358
...
368
369
370
371
372
 
373
374
375
376
...
378
379
380
 
381
382
383
384
385
 
386
387
388
389
...
399
400
401
402
403
404
405
406
 
407
408
409
410
...
412
413
414
 
415
416
417
418
419
 
420
421
422
423
424
425
 
426
427
428
429
...
436
437
438
439
440
 
441
442
443
444
445
446
 
 
447
448
449
450
451
...
454
455
456
 
457
458
459
460
461
462
 
463
464
465
 
466
467
468
 
469
470
 
471
472
473
474
...
479
480
481
 
482
483
484
485
486
487
...
493
494
495
 
496
497
 
498
499
500
501
502
...
516
517
518
 
519
520
 
521
522
523
 
524
525
526
527
...
546
547
548
 
549
550
551
552
0
@@ -12,24 +12,26 @@ static VALUE proxy_class = Qnil;
0
 
0
 static JSBool get_jsval_for_proxy(RubyLandProxy* proxy, jsval* jv)
0
 {
0
-  PREPARE_JROOTS(proxy->context, 0);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
+  PREPARE_JROOTS(context, 0);
0
 
0
   // FIXME: this is totally lame
0
   char global_key[10];
0
-  sprintf(global_key, "%x", (int)proxy->context->global);
0
+  sprintf(global_key, "%x", (int)proxy->runtime->global);
0
   
0
   if (0 == strcmp(global_key, proxy->key))
0
   {
0
-    *jv = OBJECT_TO_JSVAL(proxy->context->global);
0
+    *jv = OBJECT_TO_JSVAL(proxy->runtime->global);
0
     JRETURN;
0
   }
0
   
0
-  JCHECK(JS_GetProperty(proxy->context->js, proxy->context->gcthings, proxy->key, jv));
0
+  JCHECK(JS_GetProperty(context, proxy->runtime->gcthings, proxy->key, jv));
0
   JRETURN;
0
 }
0
 
0
-static VALUE call_js_function_value(OurContext* context, jsval target, jsval function, int argc, VALUE* argv)
0
+static VALUE call_js_function_value(JohnsonRuntime* runtime, jsval target, jsval function, int argc, VALUE* argv)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   PREPARE_RUBY_JROOTS(context, argc + 2);
0
 
0
   JROOT(target);
0
@@ -43,14 +45,14 @@ static VALUE call_js_function_value(OurContext* context, jsval target, jsval fun
0
   int i;
0
   for(i = 0; i < argc; ++i)
0
   {
0
-    JCHECK(convert_to_js(context, argv[i], &(args[i])));
0
+    JCHECK(convert_to_js(runtime, argv[i], &(args[i])));
0
     JROOT(args[i]);
0
   }
0
 
0
-  JCHECK(JS_CallFunctionValue(context->js,
0
+  JCHECK(JS_CallFunctionValue(context,
0
     JSVAL_TO_OBJECT(target), function, (unsigned) argc, args, &result));
0
 
0
-  JRETURN_RUBY(CONVERT_TO_RUBY(context, result));
0
+  JRETURN_RUBY(CONVERT_TO_RUBY(runtime, result));
0
 }
0
 
0
 /*
0
@@ -65,7 +67,8 @@ get(VALUE self, VALUE name)
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 1);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
+  PREPARE_RUBY_JROOTS(context, 1);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
@@ -75,17 +78,17 @@ get(VALUE self, VALUE name)
0
 
0
   switch(TYPE(name)) {
0
     case T_FIXNUM:
0
-      JCHECK(JS_GetElement(proxy->context->js,
0
+      JCHECK(JS_GetElement(context,
0
           JSVAL_TO_OBJECT(proxy_value), NUM2INT(name), &js_value));
0
       break;
0
     default:
0
       Check_Type(name, T_STRING);
0
-      JCHECK(JS_GetProperty(proxy->context->js,
0
+      JCHECK(JS_GetProperty(context,
0
           JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
0
       break;
0
   }
0
 
0
-  JRETURN_RUBY(CONVERT_TO_RUBY(proxy->context, js_value));
0
+  JRETURN_RUBY(CONVERT_TO_RUBY(proxy->runtime, js_value));
0
 }
0
 
0
 /*
0
@@ -99,26 +102,27 @@ set(VALUE self, VALUE name, VALUE value)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
   
0
-  PREPARE_RUBY_JROOTS(proxy->context, 2);
0
+  PREPARE_RUBY_JROOTS(context, 2);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
   JROOT(proxy_value);
0
 
0
   jsval js_value;
0
-  JCHECK(convert_to_js(proxy->context, value, &js_value));
0
+  JCHECK(convert_to_js(proxy->runtime, value, &js_value));
0
   
0
   JROOT(js_value);
0
 
0
   switch(TYPE(name)) {
0
     case T_FIXNUM:
0
-      JCHECK(JS_SetElement(proxy->context->js,
0
+      JCHECK(JS_SetElement(context,
0
               JSVAL_TO_OBJECT(proxy_value), NUM2INT(name), &js_value));
0
       break;
0
     default:
0
       Check_Type(name, T_STRING);
0
-      JCHECK(JS_SetProperty(proxy->context->js,
0
+      JCHECK(JS_SetProperty(context,
0
             JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
0
       break;
0
   }
0
@@ -137,10 +141,11 @@ function_p(VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
-  PREPARE_RUBY_JROOTS(proxy->context, 0);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
+  PREPARE_RUBY_JROOTS(context, 0);
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
-  JRETURN_RUBY(JS_TypeOfValue(proxy->context->js, proxy_value) == JSTYPE_FUNCTION ? Qtrue : Qfalse);
0
+  JRETURN_RUBY(JS_TypeOfValue(context, proxy_value) == JSTYPE_FUNCTION ? Qtrue : Qfalse);
0
 }
0
 
0
 /*
0
@@ -155,7 +160,8 @@ respond_to_p(VALUE self, VALUE sym)
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 2);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
+  PREPARE_RUBY_JROOTS(context, 2);
0
   
0
   char* name = rb_id2name(SYM2ID(sym));
0
   
0
@@ -170,10 +176,10 @@ respond_to_p(VALUE self, VALUE sym)
0
   JSObject *obj;
0
   JSBool found;
0
   
0
-  JCHECK(JS_ValueToObject(proxy->context->js, proxy_value, &obj));
0
+  JCHECK(JS_ValueToObject(context, proxy_value, &obj));
0
   JROOT(obj);
0
 
0
-  JCHECK(JS_HasProperty(proxy->context->js, obj, name, &found));
0
+  JCHECK(JS_HasProperty(context, obj, name, &found));
0
 
0
   JRETURN_RUBY(found ? Qtrue : CALL_RUBY_WRAPPER(rb_call_super, 1, &sym));
0
 }
0
@@ -195,23 +201,24 @@ native_call(int argc, VALUE* argv, VALUE self)
0
 
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
   
0
-  PREPARE_RUBY_JROOTS(proxy->context, 1);
0
+  PREPARE_RUBY_JROOTS(context, 1);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
   JROOT(proxy_value);
0
 
0
   jsval global;
0
-  JCHECK(convert_to_js(proxy->context, argv[0], &global));
0
+  JCHECK(convert_to_js(proxy->runtime, argv[0], &global));
0
 
0
-  JRETURN_RUBY(call_js_function_value(proxy->context, global, proxy_value, argc - 1, &(argv[1])));
0
+  JRETURN_RUBY(call_js_function_value(proxy->runtime, global, proxy_value, argc - 1, &(argv[1])));
0
 }
0
 
0
 static void
0
-destroy_id_array(OurContext* context, void* data)
0
+destroy_id_array(JSContext* context, void* data)
0
 {
0
-  JS_DestroyIdArray(context->js, (JSIdArray*)data);
0
+  JS_DestroyIdArray(context, (JSIdArray*)data);
0
 }
0
 
0
 /*
0
@@ -225,8 +232,9 @@ each(VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
   
0
-  PREPARE_RUBY_JROOTS(proxy->context, 5);
0
+  PREPARE_RUBY_JROOTS(context, 5);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
@@ -236,23 +244,23 @@ each(VALUE self)
0
   JROOT(value);
0
   
0
   // arrays behave like you'd expect, indexes in order
0
-  if (JS_IsArrayObject(proxy->context->js, value))
0
+  if (JS_IsArrayObject(context, value))
0
   {
0
     jsuint length;
0
-    JCHECK(JS_GetArrayLength(proxy->context->js, value, &length));
0
+    JCHECK(JS_GetArrayLength(context, value, &length));
0
     
0
     jsuint i = 0;
0
     for (i = 0; i < length; ++i)
0
     {
0
       jsval element;
0
-      JCHECK(JS_GetElement(proxy->context->js, value, (signed) i, &element));
0
-      CALL_RUBY_WRAPPER(rb_yield, convert_to_ruby(proxy->context, element));
0
+      JCHECK(JS_GetElement(context, value, (signed) i, &element));
0
+      CALL_RUBY_WRAPPER(rb_yield, convert_to_ruby(proxy->runtime, element));
0
     }
0
   }
0
   else
0
   {
0
     // not an array? behave like each on Hash; yield [key, value]
0
-    JSIdArray* ids = JS_Enumerate(proxy->context->js, value);
0
+    JSIdArray* ids = JS_Enumerate(context, value);
0
     JCHECK(ids);
0
 
0
     JCLEANUP(destroy_id_array, ids);
0
@@ -262,25 +270,25 @@ each(VALUE self)
0
     {
0
       jsval js_key, js_value;
0
 
0
-      JCHECK(JS_IdToValue(proxy->context->js, ids->vector[i], &js_key));
0
+      JCHECK(JS_IdToValue(context, ids->vector[i], &js_key));
0
       JROOT(js_key);
0
 
0
       if (JSVAL_IS_STRING(js_key))
0
       {
0
         // regular properties have string keys
0
-        JCHECK(JS_GetProperty(proxy->context->js, value,
0
+        JCHECK(JS_GetProperty(context, value,
0
           JS_GetStringBytes(JSVAL_TO_STRING(js_key)), &js_value));
0
       }
0
       else
0
       {
0
         // it's a numeric property, use array access
0
-        JCHECK(JS_GetElement(proxy->context->js, value,
0
+        JCHECK(JS_GetElement(context, value,
0
           JSVAL_TO_INT(js_key), &js_value));
0
       }
0
       JROOT(js_value);
0
 
0
-      VALUE key = CONVERT_TO_RUBY(proxy->context, js_key);
0
-      VALUE value = CONVERT_TO_RUBY(proxy->context, js_value);
0
+      VALUE key = CONVERT_TO_RUBY(proxy->runtime, js_key);
0
+      VALUE value = CONVERT_TO_RUBY(proxy->runtime, js_value);
0
 
0
       CALL_RUBY_WRAPPER(rb_yield, rb_ary_new3(2, key, value));
0
 
0
@@ -303,8 +311,9 @@ length(VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 2);
0
+  PREPARE_RUBY_JROOTS(context, 2);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
@@ -313,20 +322,20 @@ length(VALUE self)
0
   JSObject* value = JSVAL_TO_OBJECT(proxy_value);
0
   JROOT(value);
0
   
0
-  if (JS_IsArrayObject(proxy->context->js, value))
0
+  if (JS_IsArrayObject(context, value))
0
   {
0
     jsuint length;
0
-    JCHECK(JS_GetArrayLength(proxy->context->js, value, &length));
0
+    JCHECK(JS_GetArrayLength(context, value, &length));
0
 
0
     JRETURN_RUBY(INT2FIX(length));
0
   }
0
   else
0
   {
0
-    JSIdArray* ids = JS_Enumerate(proxy->context->js, value);
0
+    JSIdArray* ids = JS_Enumerate(context, value);
0
     JCHECK(ids);
0
     VALUE length = INT2FIX(ids->length);
0
     
0
-    JS_DestroyIdArray(proxy->context->js, ids);
0
+    JS_DestroyIdArray(context, ids);
0
 
0
     JRETURN_RUBY(length);
0
   }
0
@@ -334,16 +343,16 @@ length(VALUE self)
0
 
0
 /*
0
  * call-seq:
0
- *   context
0
+ *   runtime
0
  *
0
- * Returns context.
0
+ * Returns runtime.
0
  */
0
 static VALUE
0
-context(VALUE self)
0
+runtime(VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
-  return (VALUE)JS_GetContextPrivate(proxy->context->js);
0
+  return (VALUE)JS_GetRuntimePrivate(proxy->runtime->js);
0
 }
0
 
0
 /*
0
@@ -359,8 +368,9 @@ function_property_p(VALUE self, VALUE name)
0
   
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 2);
0
+  PREPARE_RUBY_JROOTS(context, 2);
0
 
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
@@ -368,12 +378,12 @@ function_property_p(VALUE self, VALUE name)
0
 
0
   jsval js_value;  
0
 
0
-  JCHECK(JS_GetProperty(proxy->context->js,
0
+  JCHECK(JS_GetProperty(context,
0
       JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
0
 
0
   JROOT(js_value);
0
 
0
-  JSType type = JS_TypeOfValue(proxy->context->js, js_value);
0
+  JSType type = JS_TypeOfValue(context, js_value);
0
 
0
   JRETURN_RUBY(type == JSTYPE_FUNCTION ? Qtrue : Qfalse);
0
 }
0
@@ -389,11 +399,12 @@ call_function_property(int argc, VALUE* argv, VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
 
0
   if (argc < 1)
0
     rb_raise(rb_eArgError, "Function name required");
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 2);
0
+  PREPARE_RUBY_JROOTS(context, 2);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
@@ -401,18 +412,18 @@ call_function_property(int argc, VALUE* argv, VALUE self)
0
 
0
   jsval function;
0
   
0
-  JCHECK(JS_GetProperty(proxy->context->js,
0
+  JCHECK(JS_GetProperty(context,
0
     JSVAL_TO_OBJECT(proxy_value), StringValueCStr(argv[0]), &function));
0
 
0
   JROOT(function);
0
 
0
-  JSType funtype = JS_TypeOfValue(proxy->context->js, function);
0
+  JSType funtype = JS_TypeOfValue(context, function);
0
   
0
   // should never be anything but a function
0
   if (funtype != JSTYPE_FUNCTION)
0
     JERROR("Specified property \"%s\" isn't a function.", StringValueCStr(argv[0]));
0
 
0
-  JRETURN_RUBY(call_js_function_value(proxy->context, proxy_value, function, argc - 1, &(argv[1])));
0
+  JRETURN_RUBY(call_js_function_value(proxy->runtime, proxy_value, function, argc - 1, &(argv[1])));
0
 }
0
 
0
 /*
0
@@ -425,15 +436,16 @@ static VALUE to_s(VALUE self)
0
 {
0
   RubyLandProxy* proxy;
0
   Data_Get_Struct(self, RubyLandProxy, proxy);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
 
0
-  PREPARE_RUBY_JROOTS(proxy->context, 1);
0
+  PREPARE_RUBY_JROOTS(context, 1);
0
   
0
   jsval proxy_value;
0
   JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
0
   JROOT(proxy_value);
0
   
0
-  JSString* str = JS_ValueToString(proxy->context->js, proxy_value);
0
-  JRETURN_RUBY(convert_jsstring_to_ruby(proxy->context, str));
0
+  JSString* str = JS_ValueToString(context, proxy_value);
0
+  JRETURN_RUBY(convert_js_string_to_ruby(proxy->runtime, str));
0
 }
0
 
0
 ///////////////////////////////////////////////////////////////////////////
0
@@ -442,20 +454,21 @@ static VALUE to_s(VALUE self)
0
 
0
 static void finalize(RubyLandProxy* proxy)
0
 {
0
-  PREPARE_RUBY_JROOTS(proxy->context, 0);
0
+  JSContext * context = johnson_get_current_context(proxy->runtime);
0
+  PREPARE_RUBY_JROOTS(context, 0);
0
   jsval proxy_value;
0
   JCHECK_RUBY(get_jsval_for_proxy(proxy, &proxy_value));
0
   
0
   // could get finalized after the context has been freed
0
-  if (proxy->context && proxy->context->jsids)
0
+  if (proxy->runtime && proxy->runtime->jsids)
0
   {
0
     // remove this proxy from the OID map
0
-    JS_HashTableRemove(proxy->context->jsids, (void *)proxy_value);
0
+    JS_HashTableRemove(proxy->runtime->jsids, (void *)proxy_value);
0
   
0
     // remove our GC handle on the JS value
0
-    JS_DeleteProperty(proxy->context->js, proxy->context->gcthings, proxy->key);
0
+    JS_DeleteProperty(context, proxy->runtime->gcthings, proxy->key);
0
     
0
-    proxy->context = 0;
0
+    proxy->runtime = 0;
0
   }
0
   
0
   free(proxy);
0
@@ -466,8 +479,9 @@ bool ruby_value_is_proxy(VALUE maybe_proxy)
0
   return proxy_class == CLASS_OF(maybe_proxy); 
0
 }
0
 
0
-JSBool unwrap_ruby_land_proxy(OurContext* context, VALUE wrapped, jsval* retval)
0
+JSBool unwrap_ruby_land_proxy(JohnsonRuntime* runtime, VALUE wrapped, jsval* retval)
0
 {
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   assert(ruby_value_is_proxy(wrapped));
0
   
0
   PREPARE_JROOTS(context, 0);
0
@@ -479,9 +493,10 @@ JSBool unwrap_ruby_land_proxy(OurContext* context, VALUE wrapped, jsval* retval)
0
   JRETURN;
0
 }
0
 
0
-VALUE make_ruby_land_proxy(OurContext* context, jsval value)
0
+VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value)
0
 {
0
-  VALUE id = (VALUE)JS_HashTableLookup(context->jsids, (void *)value);
0
+  VALUE id = (VALUE)JS_HashTableLookup(runtime->jsids, (void *)value);
0
+  JSContext * context = johnson_get_current_context(runtime);
0
   
0
   if (id)
0
   {
0
@@ -501,12 +516,12 @@ VALUE make_ruby_land_proxy(OurContext* context, jsval value)
0
     // root the value for JS GC and lookups
0
     sprintf(our_proxy->key, "%x", (int)value);
0
     
0
-    JCHECK(JS_SetProperty(context->js, context->gcthings, our_proxy->key, &value));
0
+    JCHECK(JS_SetProperty(context, runtime->gcthings, our_proxy->key, &value));
0
 
0
-    our_proxy->context = context;
0
+    our_proxy->runtime = runtime;
0
 
0
     // put the proxy OID in the id map
0
-    JCHECK(JS_HashTableAdd(context->jsids, (void *)value, (void *)rb_obj_id(proxy)));
0
+    JCHECK(JS_HashTableAdd(runtime->jsids, (void *)value, (void *)rb_obj_id(proxy)));
0
     
0
     JRETURN_RUBY(proxy);
0
   }
0
@@ -531,7 +546,7 @@ void init_Johnson_SpiderMonkey_Proxy(VALUE spidermonkey)
0
   rb_define_method(proxy_class, "to_s", to_s, 0);
0
 
0
   rb_define_private_method(proxy_class, "native_call", native_call, -1);
0
-  rb_define_private_method(proxy_class, "context", context, 0);
0
+  rb_define_private_method(proxy_class, "runtime", runtime, 0);
0
   rb_define_private_method(proxy_class, "function_property?", function_property_p, 1);
0
   rb_define_private_method(proxy_class, "call_function_property", call_function_property, -1);
0
 }
...
2
3
4
5
 
6
7
8
9
 
10
11
12
13
14
 
 
15
16
17
...
2
3
4
 
5
6
7
8
 
9
10
11
12
 
 
13
14
15
16
17
0
@@ -2,16 +2,16 @@
0
 #define JOHNSON_SPIDERMONKEY_RUBY_LAND_PROXY_H
0
 
0
 #include "spidermonkey.h"
0
-#include "context.h"
0
+#include "runtime.h"
0
 
0
 typedef struct {
0
   char key[10];
0
-  OurContext* context;
0
+  JohnsonRuntime* runtime;
0
 } RubyLandProxy;
0
 
0
 bool ruby_value_is_proxy(VALUE maybe_proxy);
0
-JSBool unwrap_ruby_land_proxy(OurContext* context, VALUE proxy, jsval* retval);
0
-VALUE make_ruby_land_proxy(OurContext* context, jsval value);
0
+JSBool unwrap_ruby_land_proxy(JohnsonRuntime* runtime, VALUE proxy, jsval* retval);
0
+VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value);
0
 void init_Johnson_SpiderMonkey_Proxy(VALUE spidermonkey);
0
 
0
 #endif
...
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
...
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
...
99
100
101
 
 
 
 
102
...
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
...
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
...
222
223
224
225
226
227
228
229
0
@@ -2,47 +2,151 @@
0
 #include "error.h"
0
 #include "global.h"
0
 #include "idhash.h"
0
+#include "conversions.h"
0
+#include "jsdbgapi.h"
0
 
0
-JSContext* johnson_get_current_context(JohnsonRuntime* runtime)
0
+/*
0
+ * call-seq:
0
+ *   global
0
+ *
0
+ * Returns the global object used for this context.
0
+ */
0
+static VALUE global(VALUE self)
0
 {
0
-  // First, see if we already have a context for the current thread.
0
-  JSContext* context = (JSContext*)JS_HashTableLookup(runtime->contexts, (void*)rb_thread_current());
0
-  
0
-  // If not,
0
-  if (!context)
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(self, JohnsonRuntime, runtime);
0
+  return convert_to_ruby(runtime, OBJECT_TO_JSVAL(runtime->global));
0
+}
0
+
0
+/*
0
+ * call-seq:
0
+ *   evaluate(script, filename=nil, linenum=nil)
0
+ *
0
+ * Evaluate +script+ with +filename+ using +linenum+
0
+ */
0
+static VALUE evaluate(int argc, VALUE* argv, VALUE self)
0
+{
0
+  VALUE script, filename, linenum;
0
+
0
+  JohnsonRuntime* runtime;
0
+  Data_Get_Struct(self, JohnsonRuntime, runtime);
0
+
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+  JohnsonContext * johnson_context = OUR_CONTEXT(context);
0
+  rb_scan_args( argc, argv, "12", &script, &filename, &linenum );
0
+
0
+  // clean things up first
0
+  johnson_context->ex = 0;
0
+  memset(johnson_context->msg, 0, MAX_EXCEPTION_MESSAGE_SIZE);
0
+
0
+  const char* filenamez = RTEST(filename) ? StringValueCStr(filename) : "none";
0
+  int linenumi = RTEST(linenum) ? NUM2INT(linenum) : 1;
0
+
0
+  jsval js;
0
+
0
+  // FIXME: should be able to pass in the 'file' name
0
+  JSBool ok = JS_EvaluateScript(context, runtime->global,
0
+    StringValuePtr(script), (unsigned)StringValueLen(script), filenamez, (unsigned)linenumi, &js);
0
+
0
+  if (!ok)
0
   {
0
-    // try and create one.
0
-    if ((context = JS_NewContext(runtime->js, 8192)))
0
+    if (JS_IsExceptionPending(context))
0
     {
0
-      // See if the runtime already has a shared global object.
0
-      JSObject* global = runtime->global;
0
-      
0
-      // If it does, use it. If not,
0
-      if (!global)
0
-        // create one of our global objects.
0
-        global = johnson_create_global_object(context);
0
+      // If there's an exception pending here, it's a syntax error.
0
+      JS_GetPendingException(context, &johnson_context->ex);
0
+      JS_ClearPendingException(context);
0
+    }
0
 
0
-      // Manually set the context's global object.
0
-      JS_SetGlobalObject(context, global);
0
-      
0
-      // Register this context (thread -> context) for lookup next time.
0
-      JS_HashTableAdd(runtime->contexts, (void*)rb_thread_current(), (void*) context);
0
+    if (johnson_context->ex)
0
+    {
0
+      return rb_funcall(self, rb_intern("handle_js_exception"),
0
+        1, convert_to_ruby(runtime, johnson_context->ex));
0
       
0
-      // Success.
0
-      return context;
0
+      // VALUE message, file, line, stack;
0
+      // 
0
+      // jsval js_message;
0
+      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "message", &js_message));
0
+      // message = convert_to_ruby(context, js_message);
0
+      // 
0
+      // jsval js_file;
0
+      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "fileName", &js_file));
0
+      // file = convert_to_ruby(context, js_file);
0
+      // 
0
+      // jsval js_line;
0
+      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "lineNumber", &js_line));
0
+      // line = convert_to_ruby(context, js_line);
0
+      // 
0
+      // jsval js_stack;
0
+      // assert(JS_GetProperty(context->js, JSVAL_TO_OBJECT(context->ex), "stack", &js_stack));
0
+      // stack = convert_to_ruby(context, js_stack);
0
+      // 
0
+      // return rb_funcall(self, rb_intern("handle_js_exception"),
0
+      //   4, message, file, line, stack);
0
     }
0
-
0
-    // Something went wrong! If a context was created,
0
-    if (context)
0
-      // destroy it safely.
0
-      JS_DestroyContext(context);
0
     
0
-    // Scream for help.
0
-    Johnson_Error_raise("Unable to create Johnson::SpiderMonkey::Runtime!");
0
+    char* msg = johnson_context->msg;
0
+
0
+    // toString() whatever the exception object is (if we have one)
0
+    if (johnson_context->ex)
0
+      msg = JS_GetStringBytes(JS_ValueToString(context, johnson_context->ex));
0
+
0
+    return Johnson_Error_raise(msg);
0
   }
0
-  
0
-  // Success. Already had a context for the current thread.
0
-  return context;
0
+
0
+  return convert_to_ruby(runtime, js);
0
+}
0
+
0
+/*
0
+ * call-seq:
0
+ *   debugger=(debugger)
0
+ *
0
+ * Sets a debugger object
0
+ */
0
+static VALUE
0
+set_debugger(VALUE self, VALUE debugger)
0
+{
0
+  JohnsonRuntime* runtime;
0
+  JSDebugHooks* debug_hooks;
0
+
0
+  Data_Get_Struct(self, JohnsonRuntime, runtime);
0
+  Data_Get_Struct(debugger, JSDebugHooks, debug_hooks);
0
+
0
+  JSContext * context = johnson_get_current_context(runtime);
0
+
0
+  JS_SetInterrupt(          runtime->js,
0
+                            debug_hooks->interruptHandler,
0
+                            debug_hooks->interruptHandlerData);
0
+  JS_SetNewScriptHook(      runtime->js,
0
+                            debug_hooks->newScriptHook,
0
+                            debug_hooks->newScriptHookData);
0
+  JS_SetDestroyScriptHook(  runtime->js,
0
+                            debug_hooks->destroyScriptHook,
0
+                            debug_hooks->destroyScriptHookData);
0
+  JS_SetDebuggerHandler(    runtime->js,
0
+                            debug_hooks->debuggerHandler,
0
+                            debug_hooks->debuggerHandlerData);
0
+  JS_SetSourceHandler(      runtime->js,
0
+                            debug_hooks->sourceHandler,
0
+                            debug_hooks->sourceHandlerData);
0
+  JS_SetExecuteHook(        runtime->js,
0
+                            debug_hooks->executeHook,
0
+                            debug_hooks->executeHookData);
0
+  JS_SetCallHook(           runtime->js,
0
+                            debug_hooks->callHook,
0
+                            debug_hooks->callHookData);
0
+  JS_SetObjectHook(         runtime->js,
0
+                            debug_hooks->objectHook,
0
+                            debug_hooks->objectHookData);
0
+  JS_SetThrowHook(          runtime->js,
0
+                            debug_hooks->throwHook,
0
+                            debug_hooks->throwHookData);
0
+  JS_SetDebugErrorHook(     runtime->js,
0
+                            debug_hooks->debugErrorHook,
0
+                            debug_hooks->debugErrorHookData);
0
+
0
+  JS_SetContextDebugHooks(context, debug_hooks);
0
+
0
+  return debugger;
0
 }
0
 
0
 static VALUE
0
@@ -51,32 +155,51 @@ initialize_native(VALUE self, VALUE UNUSED(options))
0
   JohnsonRuntime* runtime;
0
   Data_Get_Struct(self, JohnsonRuntime, runtime);
0
   
0
+  bool gcthings_rooted_p = false;
0
+
0
   if ((runtime->js = JS_NewRuntime(0x100000))
0
-    && (runtime->contexts = create_id_hash()))
0
+    && (runtime->jsids = create_id_hash())
0
+    && (runtime->rbids = create_id_hash())
0
+  )
0
   {
0
+    JS_SetRuntimePrivate(runtime->js, (void *)self);
0
     JSContext* context = johnson_get_current_context(runtime);
0
-    runtime->global = JS_GetGlobalObject(context);    
0
-    JS_AddNamedRoot(context, &(runtime->global), "runtime->global");
0
-    
0
-    return self;
0
+    if(
0
+        (runtime->gcthings = JS_NewObject(context, NULL, 0, 0))
0
+        &&(runtime->global = JS_GetGlobalObject(context))
0
+        &&(gcthings_rooted_p = JS_AddNamedRoot(context, &(runtime->global), "runtime->global"))
0
+    ) {
0
+      return self;
0
+    }
0
+    if (gcthings_rooted_p)
0
+      JS_RemoveRoot(context, &(runtime->gcthings));
0
   }
0
-  
0
-  if (runtime->contexts)
0
-    JS_HashTableDestroy(runtime->contexts);
0
-  
0
+
0
+
0
+  if (runtime->rbids)
0
+    JS_HashTableDestroy(runtime->rbids);
0
+
0
+  if (runtime->jsids)
0
+    JS_HashTableDestroy(runtime->jsids);
0
+
0
   if (runtime->js)
0
     JS_DestroyRuntime(runtime->js);
0
     
0
   return Johnson_Error_raise("Couldn't initialize the runtime!");
0
 }
0
 
0
+JSContext* johnson_get_current_context(JohnsonRuntime * runtime)
0
+{
0
+  JohnsonContext * context = NULL;
0
+  VALUE self = (VALUE)JS_GetRuntimePrivate(runtime->js);
0
+  Data_Get_Struct(rb_funcall(self, rb_intern("current_context"), 0), JohnsonContext, context);
0
+  return context->js;
0
+}
0
+
0
 static void deallocate(JohnsonRuntime* runtime)
0
 {
0
   JS_RemoveRoot(johnson_get_current_context(runtime), &(runtime->global));
0
   
0
-  JS_HashTableDestroy(runtime->contexts);
0
-  runtime->contexts = 0;
0
-  
0
   JSContext *context;
0
   JSContext *iterator = NULL;
0
 
0
@@ -99,4 +222,8 @@ void init_Johnson_SpiderMonkey_Runtime(VALUE spidermonkey)
0
 
0
   rb_define_alloc_func(klass, allocate);
0
   rb_define_private_method(klass, "initialize_native", initialize_native, 1);
0
+
0
+  rb_define_method(klass, "global", global, 0);
0
+  rb_define_method(klass, "evaluate", evaluate, -1);
0
+  rb_define_method(klass, "debugger=", set_debugger, 1);
0
 }
...
4
5
6
7
8
9
 
 
 
 
10
11
12
...
4
5
6
 
7
8
9
10
11
12
13
14
15
0
@@ -4,9 +4,12 @@
0
 #include "spidermonkey.h"
0
 
0
 typedef struct {
0
-  JSHashTable* contexts;
0
   JSObject* global;
0
   JSRuntime* js;
0
+
0
+  JSHashTable *jsids; // jsid -> rbid
0
+  JSHashTable *rbids; // rbid -> jsid
0
+  JSObject *gcthings;
0
 } JohnsonRuntime;
0
 
0
 JSContext* johnson_get_current_context(JohnsonRuntime* runtime);
...
62
63
64
65
 
66
67
68
...
62
63
64
 
65
66
67
68
0
@@ -62,7 +62,7 @@ Johnson.require = function(file) {
0
     
0
     if(Ruby.File.send("file?", path)) {
0
       Johnson.required[file] = true;
0
-      Johnson.currentContext.load(path);
0
+      Johnson.runtime.load(path);
0
       
0
       return true;
0
     }
...
24
25
26
27
 
28
29
30
...
33
34
35
36
37
 
 
38
39
 
40
41
42
...
24
25
26
 
27
28
29
30
...
33
34
35
 
 
36
37
38
 
39
40
41
42
0
@@ -24,7 +24,7 @@ require "johnson/spidermonkey/debugger"
0
 require "johnson/spidermonkey/immutable_node"
0
 
0
 # the 'public' interface
0
-require "johnson/context"
0
+require "johnson/runtime"
0
 require "johnson/parser"
0
 
0
 $LOAD_PATH.push(File.expand_path("#{File.dirname(__FILE__)}/../js"))
0
@@ -33,10 +33,10 @@ module Johnson
0
   PRELUDE = IO.read(File.dirname(__FILE__) + "/../js/johnson/prelude.js")
0
   
0
   def self.evaluate(expression, vars={})
0
-    context = Johnson::Context.new
0
-    vars.each { |key, value| context[key] = value }
0
+    runtime = Johnson::Runtime.new
0
+    vars.each { |key, value| runtime[key] = value }
0
     
0
-    context.evaluate(expression)
0
+    runtime.evaluate(expression)
0
   end
0
   
0
   def self.parse(js, *args)
...
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
...
1
2
3
 
 
4
5
6
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
9
10
0
@@ -1,37 +1,10 @@
0
 module Johnson #:nodoc:
0
   module SpiderMonkey #:nodoc:
0
     class Context # native
0
-      def initialize(options={})
0
-        initialize_native(options)
0
+      def initialize(runtime, options={})
0
+        @runtime = runtime
0
+        initialize_native(runtime, options)
0
         @gcthings = {}
0
-        self["Ruby"] = Object
0
-      end
0
-      
0
-      def [](key)
0
-        global[key]
0
-      end
0
-      
0
-      def []=(key, value)
0
-        global[key] = value
0
-      end
0
-            
0
-      protected
0
-      
0
-      def handle_js_exception(jsex)
0
-        raise jsex if Exception === jsex
0
-        raise Johnson::Error.new(jsex.to_s) unless Johnson::SpiderMonkey::RubyLandProxy === jsex
0
-        
0
-        # FIXME: sanitize stack traces
0
-        stack = jsex.stack rescue nil
0
-        
0
-        ex = Johnson::Error.new(jsex)
0
-        if stack
0
-          ex.set_backtrace(stack.split("\n") + caller)
0
-        else
0
-          ex.set_backtrace(caller)
0
-        end
0
-        
0
-        raise ex
0
       end
0
       
0
       # called from js_land_proxy.c:make_js_land_proxy
...
16
17
18
19
 
20
21
22
...
16
17
18
 
19
20
21
22
0
@@ -16,7 +16,7 @@ module Johnson #:nodoc:
0
       end
0
 
0
       def call(*args)
0
-        call_using(context.global, *args)
0
+        call_using(runtime.global, *args)
0
       end
0
 
0
       def call_using(this, *args)
...
3
4
5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
7
8
...
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
0
@@ -3,6 +3,39 @@ module Johnson #:nodoc:
0
     class Runtime # native
0
       def initialize(options={})
0
         initialize_native(options)
0
+        self["Ruby"] = Object
0
+      end
0
+
0
+      def current_context
0
+        contexts = (Thread.current[:johson_context_map] ||= {})
0
+        contexts[self.object_id] ||= Context.new(self)
0
+      end
0
+
0
+      def [](key)
0
+        global[key]
0
+      end
0
+      
0
+      def []=(key, value)
0
+        global[key] = value
0
+      end
0
+
0
+      protected
0
+      
0
+      def handle_js_exception(jsex)
0
+        raise jsex if Exception === jsex
0
+        raise Johnson::Error.new(jsex.to_s) unless Johnson::SpiderMonkey::RubyLandProxy === jsex
0
+        
0
+        # FIXME: sanitize stack traces
0
+        stack = jsex.stack rescue nil
0
+        
0
+        ex = Johnson::Error.new(jsex)
0
+        if stack
0
+          ex.set_backtrace(stack.split("\n") + caller)
0
+        else
0
+          ex.set_backtrace(caller)
0
+        end
0
+        
0
+        raise ex
0
       end
0
     end
0
   end
...
21
22
23
24
25
 
 
26
27
28
29
30
31
 
 
 
32
33
34
...
21
22
23
 
 
24
25
26
27
28
 
 
 
29
30
31
32
33
34
0
@@ -21,14 +21,14 @@ module Johnson
0
     undef :default_test
0
     
0
     def assert_js(expression, options={})
0
-      context = options[:context] || @context
0
-      assert(context.evaluate(expression), "Expected JS expression [#{expression}] to be true.")
0
+      runtime = options[:runtime] || @runtime
0
+      assert(runtime.evaluate(expression), "Expected JS expression [#{expression}] to be true.")
0
     end
0
     
0
     def assert_js_equal(expected, expression, options={})
0
-      context = options.delete(:context) || @context
0
-      options.each { |k, v| context[k.to_s] = v }
0
-      assert_equal(expected, context.evaluate(expression))
0
+      runtime = options.delete(:runtime) || @runtime
0
+      options.each { |k, v| runtime[k.to_s] = v }
0
+      assert_equal(expected, runtime.evaluate(expression))
0
     end
0
   end
0
 
...
3
4
5
6
7
 
 
8
9
10
11
12
 
13
14
 
15
16
17
...
3
4
5
 
 
6
7
8
9
10
11
 
12
13
 
14
15
16
17
0
@@ -3,15 +3,15 @@ require File.expand_path(File.join(File.dirname(__FILE__), "/../helper"))
0
 module Johnson
0
   class BrowserTest < Johnson::TestCase
0
     def setup
0
-      @context = Johnson::Context.new
0
-      @context.evaluate('Johnson.require("johnson/browser");')
0
+      @runtime = Johnson::Runtime.new
0
+      @runtime.evaluate('Johnson.require("johnson/browser");')
0
     end
0
 
0
     def test_set_location_returns_location
0
       filename = "file://#{File.expand_path(__FILE__)}"
0
-      @context.evaluate("window.location = '#{filename}'")
0
+      @runtime.evaluate("window.location = '#{filename}'")
0
       uri = URI.parse(filename)
0
-      assert_equal(uri.to_s, @context.evaluate('window.location').to_s)
0
+      assert_equal(uri.to_s, @runtime.evaluate('window.location').to_s)
0
     end
0
   end
0
 end
...
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
...
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
0
@@ -4,32 +4,32 @@ module Johnson
0
   module Conversions
0
     class ArrayTest < Johnson::TestCase
0
       def setup
0
-        @context = Johnson::Context.new
0
+        @runtime = Johnson::Runtime.new
0
       end
0
       
0
       def test_array_index_get
0
-        @context[:list] = [1, 2, 3, 4]
0
-        assert_equal(1, @context.evaluate("list[0]"))
0
+        @runtime[:list] = [1, 2, 3, 4]
0
+        assert_equal(1, @runtime.evaluate("list[0]"))
0
       end
0
 
0
       def test_array_index_set
0
-        @context[:list] = []
0
-        @context.evaluate("list[0] = 42")
0
-        assert_equal(42, @context[:list][0])
0
+        @runtime[:list] = []
0
+        @runtime.evaluate("list[0] = 42")
0
+        assert_equal(42, @runtime[:list][0])
0
       end
0
 
0
       def test_array_works_with_for_in
0
         list = [1, 2, 3, 4]
0
 
0
-        @context['alert'] = lambda { |x| p x }
0
-        @context['list'] = list
0
-        @context.evaluate("
0
+        @runtime['alert'] = lambda { |x| p x }
0
+        @runtime['list'] = list
0
+        @runtime.evaluate("
0
           var new_list = [];
0
           for(x in list) {
0
             new_list.push(x + 1);
0
           }
0
         ")
0
-        assert_equal(list.map { |x| x + 1}, @context['new_list'].to_a)
0
+        assert_equal(list.map { |x| x + 1}, @runtime['new_list'].to_a)
0
       end
0
     end
0
   end
...
4
5
6
7
 
8
9
10
11
12
 
 
13
14
15
16
17
 
 
18
19
20
...
4
5
6
 
7
8
9
10
 
 
11
12
13
14
15
 
 
16
17
18
19
20
0
@@ -4,17 +4,17 @@ module Johnson
0
   module Conversions
0
     class BooleanTest < Johnson::TestCase
0
       def setup
0
-        @context = Johnson::Context.new
0
+        @runtime = Johnson::Runtime.new
0
       end
0
       
0
       def test_truthiness
0
-        @context[:v] = true
0
-        assert_same(true, @context.evaluate("v === true"))
0
+        @runtime[:v] = true
0
+        assert_same(true, @runtime.evaluate("v === true"))
0
       end
0
 
0
       def test_dirty_lies
0
-        @context[:v] = false
0
-        assert_same(false, @context.evaluate("v === true"))
0
+        @runtime[:v] = false
0
+        assert_same(false, @runtime.evaluate("v === true"))
0
       end
0
     end
0
   end