Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 576 lines (437 sloc) 17.188 kb
e18f74d @jbarnette Renaming proxies for clarity.
authored
1 #include "js_land_proxy.h"
dc42336 @matthewd Deal with a couple of minor warnings.
matthewd authored
2 #include "conversions.h"
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
3
4 static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval);
5 static JSBool set(JSContext* context, JSObject* obj, jsval id, jsval* retval);
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
6 static JSBool construct(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
7 static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN flags, JSObject **objp);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
8 static JSBool call(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval);
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
9 static void finalize(JSContext* context, JSObject* obj);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
10
510f1b5 @jbarnette Fix some vestigal renaming issues.
authored
11 static JSClass JSLandProxyClass = {
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
12 "JSLandProxy", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
13 JS_PropertyStub,
14 JS_PropertyStub,
15 get,
16 set,
17 JS_EnumerateStub,
d3286d8 @jbarnette Fixing compiler warnings.
authored
18 (JSResolveOp) resolve,
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
19 JS_ConvertStub,
20 finalize
21 };
22
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
23 static JSClass JSLandClassProxyClass = {
24 "JSLandClassProxy", JSCLASS_HAS_PRIVATE,
25 JS_PropertyStub,
26 JS_PropertyStub,
27 get,
28 set,
29 JS_EnumerateStub,
30 JS_ResolveStub,
31 JS_ConvertStub,
32 finalize,
33 NULL,
34 NULL,
35 NULL,
36 construct
37 };
38
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
39 static JSClass JSLandCallableProxyClass = {
40 "JSLandCallableProxy", JSCLASS_HAS_PRIVATE,
41 JS_PropertyStub,
42 JS_PropertyStub,
f518879 @jbarnette Any Rubyland object that responds to call can be called as a function in...
authored
43 get,
44 set,
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
45 JS_EnumerateStub,
46 JS_ResolveStub,
47 JS_ConvertStub,
48 finalize,
49 NULL,
50 NULL,
51 call
52 };
53
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
54 static VALUE call_ruby_from_js_invoke(VALUE args)
55 {
56 VALUE self = rb_ary_pop(args);
57 VALUE id = rb_ary_pop(args);
58 return rb_apply(self, SYM2ID(id), args);
59 }
60
61 JSBool call_ruby_from_js_va(OurContext* context, VALUE* result, VALUE self, ID id, int argc, va_list va)
62 {
63 VALUE old_errinfo = ruby_errinfo;
64 VALUE args = rb_ary_new2(argc + 2);
65
66 int i;
67 for(i = 0; i < argc; i++)
68 rb_ary_store(args, i, va_arg(va, VALUE));
69
70 rb_ary_store(args, argc, ID2SYM(id));
71 rb_ary_store(args, argc + 1, self);
72
73 int state;
74 *result = rb_protect(call_ruby_from_js_invoke, args, &state);
75
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
76 if (state)
77 return report_ruby_error_in_js(context, state, old_errinfo);
78
79 return JS_TRUE;
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
80 }
81
82 JSBool call_ruby_from_js(OurContext* context, jsval* retval, VALUE self, ID id, int argc, ...)
83 {
84 VALUE result;
85 va_list va;
86 va_start(va, argc);
87 JSBool okay = call_ruby_from_js_va(context, &result, self, id, argc, va);
88 va_end(va);
89 if (!okay) return JS_FALSE;
90 return retval ? convert_to_js(context, result, retval) : JS_TRUE;
91 }
92
93 JSBool call_ruby_from_js2(OurContext* context, VALUE* retval, VALUE self, ID id, int argc, ...)
94 {
95 va_list va;
96 va_start(va, argc);
97 JSBool okay = call_ruby_from_js_va(context, retval, self, id, argc, va);
98 va_end(va);
99 return okay;
100 }
101
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
102 static bool autovivified_p(VALUE UNUSED(ruby_context), VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
103 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
104 return RTEST(rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivified?"), 2,
105 self, rb_str_new2(name)));
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
106 }
107
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
108 static bool const_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
109 {
110 return rb_obj_is_kind_of(self, rb_cModule)
111 && rb_is_const_id(rb_intern(name))
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
112 && RTEST( rb_funcall(self, rb_intern("const_defined?"), 1, ID2SYM(rb_intern(name))) );
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
113 }
114
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
115 static bool global_p(char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
116 {
117 return rb_ary_includes(rb_f_global_variables(), rb_str_new2(name));
118 }
119
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
120 static bool method_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
121 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
122 return RTEST( rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern(name))) );
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
123 }
124
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
125 static bool attribute_p(VALUE self, char* name)
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
126 {
127 if (!method_p(self, name))
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
128 return false;
5447b86 @matthewd Be a little more certain that we've got a METHOD* before we poke it.
matthewd authored
129
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
130 VALUE rb_id = rb_intern(name);
131 VALUE rb_method = rb_funcall(self, rb_intern("method"), 1, ID2SYM(rb_id));
132
5447b86 @matthewd Be a little more certain that we've got a METHOD* before we poke it.
matthewd authored
133 if (TYPE(rb_method) == T_DATA)
134 {
135 VALUE klass = CLASS_OF(rb_method);
136 if (klass == rb_cMethod)
137 {
138 METHOD* method;
139 Data_Get_Struct(rb_method, METHOD, method);
140
141 if (method && nd_type(method->body) == NODE_IVAR)
142 return true;
143 }
144 }
145
146 return RTEST(rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
147 rb_intern("js_property?"), 2, self, ID2SYM(rb_id)));
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
148 }
149
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
150 static bool indexable_p(VALUE self)
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
151 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
152 return RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]"))));
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
153 }
154
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
155 static bool has_key_p(VALUE self, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
156 {
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
157 return RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]"))))
158 && RTEST(rb_funcall(self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("key?"))))
159 && RTEST(rb_funcall(self, rb_intern("key?"), 1, rb_str_new2(name)));
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
160 }
161
0746d92 @matthewd Use C99 bool for simple conditionals, and JSBool only for JS engine.
matthewd authored
162 static bool respond_to_p(JSContext* js_context, JSObject* obj, char* name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
163 {
97b8244 @matthewd Root everything in sight.
matthewd authored
164 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
165
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
166 OurContext* context;
167 Data_Get_Struct(ruby_context, OurContext, context);
97b8244 @matthewd Root everything in sight.
matthewd authored
168
169 VALUE self = (VALUE)JS_GetInstancePrivate(
170 context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
171
172 if (!self) return false;
173
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
174 return autovivified_p(ruby_context, self, name)
175 || const_p(self, name)
176 || global_p(name)
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
177 || attribute_p(self, name)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
178 || method_p(self, name)
179 || has_key_p(self, name);
180 }
181
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
182 static jsval evaluate_js_property_expression(OurContext * context, const char * property, jsval* retval) {
bda2acd @matthewd Merged up to removal of vendor/spidermonkey.
matthewd authored
183 return JS_EvaluateScript(context->js, context->global,
184 property, strlen(property), "johnson:evaluate_js_property_expression", 1,
185 retval);
63b6e8d @tenderlove reducing the iterator code
tenderlove authored
186 }
187
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
188 static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
189 {
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
190 // pull out our Ruby context, which is embedded in js_context
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
191
97b8244 @matthewd Root everything in sight.
matthewd authored
192 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
193
194 // get our struct, which is embedded in ruby_context
195
196 OurContext* context;
197 Data_Get_Struct(ruby_context, OurContext, context);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
198
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
199 PREPARE_JROOTS(context, 1, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
200 JROOT(id);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
201
202 // get the Ruby object that backs this proxy
203
97b8244 @matthewd Root everything in sight.
matthewd authored
204 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
205
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
206 // Short-circuit for numeric indexes
207
208 if (JSVAL_IS_INT(id))
209 {
97b8244 @matthewd Root everything in sight.
matthewd authored
210 if (indexable_p(self)) {
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
211 VALUE idx = INT2FIX(JSVAL_TO_INT(id));
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
212 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("[]"), 1, idx));
97b8244 @matthewd Root everything in sight.
matthewd authored
213 }
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
214
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
215 JRETURN;
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
216 }
217
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
218 char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
219 VALUE ruby_id = rb_intern(name);
97b8244 @matthewd Root everything in sight.
matthewd authored
220
d45a2d5 @jbarnette Added some notes for the future.
authored
221 // FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable
222
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
223 if (!strcasecmp("__iterator__", name)) {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
224 JCHECK(evaluate_js_property_expression(context, "Johnson.Generator.create", retval));
576e1fe #28 #23 arrays work in js land and so does for .. in
Aaron Patterson authored
225 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
226
204c021 switching to hash based dynamic properties
Aaron Patterson authored
227 // if the Ruby object has a dynamic js property with a key
228 // matching the property we're looking for, pull the value out of
229 // that map.
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
230
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
231 else if (autovivified_p(ruby_context, self, name))
204c021 switching to hash based dynamic properties
Aaron Patterson authored
232 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
233 JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
234 rb_intern("autovivified"), 2, self, rb_str_new2(name)));
204c021 switching to hash based dynamic properties
Aaron Patterson authored
235 }
236
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
237 // if the Ruby object is a Module or Class and has a matching
238 // const defined, return the converted result of const_get
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
239
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
240 else if (const_p(self, name))
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
241 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
242 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("const_get"),
243 1, ID2SYM(ruby_id)));
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
244 }
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
245
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
246 // otherwise, if it's a global, return the global
247 else if (global_p(name))
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
248 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
249 JCHECK(convert_to_js(context, rb_gv_get(name), retval));
1f9f150 @tenderlove giving spidermonkey access to ruby constants
tenderlove authored
250 }
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
251
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
252 // otherwise, if the Ruby object has a an attribute method matching
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
253 // the property we're trying to get, call it and return the converted result
254
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
255 else if (attribute_p(self, name))
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
256 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
257 JCHECK(call_ruby_from_js(context, retval, self, ruby_id, 0));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
258 }
5ccbbfa Constants can be accessed as properties in JSLand.
jbarnette authored
259
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
260 // otherwise, if the Ruby object quacks sorta like a hash (it responds to
261 // "[]" and "key?"), index it by key and return the converted result
262
263 else if (has_key_p(self, name))
264 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
265 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("[]"), 1, rb_str_new2(name)));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
266 }
267
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
268 // otherwise, it's a method being accessed as a property, which means
269 // we need to return a lambda
270
cfcba6d @jbarnette Added a few more FIXMEs.
authored
271 // FIXME: this should really wrap the Method for 'name' in a JS class
272 // rather than generating a wrapper Proc
273
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
274 else if (method_p(self, name))
275 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
276 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("method"), 1, rb_str_new2(name)));
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
277 }
5a4b5f0 @matthewd Do a slightly better job of keeping +id+ rooted as long as we need +name...
matthewd authored
278
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
279 // else it's undefined (JS_VOID) by default
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
280 JRETURN;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
281 }
282
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
283 // called for lazily resolved properties, which should go away
284 static JSBool get_and_destroy_resolved_property(
285 JSContext* js_context, JSObject* obj, jsval id, jsval* retval)
286 {
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
287 PREPARE_JROOTS(OUR_CONTEXT(js_context), 1, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
288 JROOT(id);
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
289 char* name = JS_GetStringBytes(JSVAL_TO_STRING(id));
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
290 JCHECK(JS_DeleteProperty(js_context, obj, name));
291 JCHECK(get(js_context, obj, id, retval));
292 JRETURN;
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
293 }
294
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
295 static JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value)
296 {
97b8244 @matthewd Root everything in sight.
matthewd authored
297 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
298
299 OurContext* context;
300 Data_Get_Struct(ruby_context, OurContext, context);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
301
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
302 PREPARE_JROOTS(context, 2, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
303 JROOT(id);
304 JROOT_PTR(value);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
305
97b8244 @matthewd Root everything in sight.
matthewd authored
306 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
307
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
308 // Short-circuit for numeric indexes
309
310 if (JSVAL_IS_INT(id))
311 {
312 if (indexable_p(self))
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
313 {
314 VALUE idx = INT2FIX(JSVAL_TO_INT(id));
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
315 VALUE val = JPROTECT(convert_to_ruby(context, *value));
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
316
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
317 JCHECK(call_ruby_from_js(context, NULL, self, rb_intern("[]="), 2, idx, val));
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
318 }
97b8244 @matthewd Root everything in sight.
matthewd authored
319
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
320 JRETURN;
e0d5bf2 @jbarnette Simple implementation for working numeric array indexes.
authored
321 }
322
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
323 VALUE ruby_key = JPROTECT(convert_to_ruby(context, id));
324 VALUE ruby_value = JPROTECT(convert_to_ruby(context, *value));
97b8244 @matthewd Root everything in sight.
matthewd authored
325
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
326 VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("="));
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
327 VALUE setter_id = rb_intern(StringValueCStr(setter));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
328
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
329 VALUE settable_p, indexable_p;
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
330 JCHECK(call_ruby_from_js2(context, &settable_p, self, rb_intern("respond_to?"), 1, ID2SYM(setter_id)));
331 JCHECK(call_ruby_from_js2(context, &indexable_p, self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]="))));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
332
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
333 if (settable_p)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
334 {
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
335 VALUE method, arity;
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
336 JCHECK(call_ruby_from_js2(context, &method, self, rb_intern("method"), 1, ID2SYM(setter_id)));
337 JCHECK(call_ruby_from_js2(context, &arity, method, rb_intern("arity"), 0));
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
338
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
339 // if the Ruby object has a 1-arity method named "property=",
340 // call it with the converted value
341
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
342 if (NUM2INT(arity) == 1)
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
343 JCHECK(call_ruby_from_js(context, NULL, self, setter_id, 1, ruby_value));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
344 }
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
345 else if(indexable_p)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
346 {
347 // otherwise, if the Ruby object quacks sorta like a hash for assignment
348 // (it responds to "[]="), assign it by key
349
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
350 JCHECK(call_ruby_from_js(context, NULL, self, rb_intern("[]="), 2, ruby_key, ruby_value));
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
351 }
352 else
353 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
354 JCHECK(call_ruby_from_js(context, NULL, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"),
355 3, self, ruby_key, ruby_value));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
356 }
97b8244 @matthewd Root everything in sight.
matthewd authored
357
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
358 JRETURN;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
359 }
360
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
361 static JSBool construct(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* retval)
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
362 {
97b8244 @matthewd Root everything in sight.
matthewd authored
363 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
364
365 OurContext* context;
366 Data_Get_Struct(ruby_context, OurContext, context);
367
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
368 PREPARE_JROOTS(context, 0, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
369
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
370 VALUE klass = JPROTECT(convert_to_ruby(context, JS_ARGV_CALLEE(argv)));
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
371 VALUE args = rb_ary_new();
372
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
373 uintN i;
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
374 for (i = 0; i < argc; ++i)
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
375 rb_ary_push(args, JPROTECT(convert_to_ruby(context, argv[i])));
46ffbc1 @jbarnette JSland proxies of Ruby classes have working constructors. [#29 state:res...
authored
376
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
377 JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
378 rb_intern("send_with_possible_block"), 3, klass, ID2SYM(rb_intern("new")), args));
379 JRETURN;
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
380 }
381
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
382 static JSBool resolve(JSContext *js_context, JSObject *obj, jsval id, uintN UNUSED(flags), JSObject **objp)
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
383 {
97b8244 @matthewd Root everything in sight.
matthewd authored
384 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
385
386 OurContext* context;
387 Data_Get_Struct(ruby_context, OurContext, context);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
388
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
389 PREPARE_JROOTS(context, 1, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
390 JROOT(id);
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
391
392 char* name = JS_GetStringBytes(JS_ValueToString(js_context, id));
97b8244 @matthewd Root everything in sight.
matthewd authored
393
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
394 if (respond_to_p(js_context, obj, name))
395 {
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
396 JCHECK(JS_DefineProperty(js_context, obj, name, JSVAL_VOID,
397 get_and_destroy_resolved_property, set, JSPROP_ENUMERATE));
97b8244 @matthewd Root everything in sight.
matthewd authored
398
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
399 *objp = obj;
400 }
97b8244 @matthewd Root everything in sight.
matthewd authored
401
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
402 JRETURN;
6b3683d @jbarnette Make with() work. [#31 state:resolved]
authored
403 }
404
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
405 static JSBool to_string(JSContext* js_context, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* retval)
406 {
407 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
408
409 OurContext* context;
410 Data_Get_Struct(ruby_context, OurContext, context);
411
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
412 PREPARE_JROOTS(context, 0, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
413
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
414 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
415
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
416 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("to_s"), 0));
417 JRETURN;
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
418 }
419
420 static JSBool to_array(JSContext* js_context, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* retval)
421 {
422 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
423
424 OurContext* context;
425 Data_Get_Struct(ruby_context, OurContext, context);
426
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
427 PREPARE_JROOTS(context, 0, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
428
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
429 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
430
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
431 JCHECK(call_ruby_from_js(context, retval, self, rb_intern("to_a"), 0));
432 JRETURN;
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
433 }
434
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
435 static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval)
436 {
97b8244 @matthewd Root everything in sight.
matthewd authored
437 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
438
439 OurContext* context;
440 Data_Get_Struct(ruby_context, OurContext, context);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
441
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
442 PREPARE_JROOTS(context, 0, 0);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
443
97b8244 @matthewd Root everything in sight.
matthewd authored
444 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL);
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
445
97b8244 @matthewd Root everything in sight.
matthewd authored
446 assert(argc >= 2);
447
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
448 char* key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
449 VALUE ruby_id = rb_intern(key);
450
78f8bf9 @jbarnette Naming and formatting nitpicks.
authored
451 // FIXME: this is horrible and lazy, to_a comes from enumerable on proxy (argv[1] is a JSArray)
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
452 VALUE args;
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
453 JCHECK(call_ruby_from_js2(context, &args, JPROTECT(convert_to_ruby(context, argv[1])), rb_intern("to_a"), 0));
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
454
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
455 JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
456 rb_intern("send_with_possible_block"), 3, self, ID2SYM(ruby_id), args));
457
458 JRETURN;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
459 }
460
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
461 static JSBool call(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* retval)
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
462 {
97b8244 @matthewd Root everything in sight.
matthewd authored
463 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
464
465 OurContext* context;
466 Data_Get_Struct(ruby_context, OurContext, context);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
467
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
468 PREPARE_JROOTS(context, 0, 0);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
469
97b8244 @matthewd Root everything in sight.
matthewd authored
470 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
471
472 VALUE args = rb_ary_new();
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
473
474 uintN i;
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
475 for (i = 0; i < argc; ++i)
15f8763 @matthewd Deal with a couple of places that Ruby exceptions can leak through JSLan...
matthewd authored
476 rb_ary_push(args, JPROTECT(convert_to_ruby(context, argv[i])));
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
477
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
478 JCHECK(call_ruby_from_js(context, retval, Johnson_SpiderMonkey_JSLandProxy(),
479 rb_intern("send_with_possible_block"), 3, self, ID2SYM(rb_intern("call")), args));
480 JRETURN;
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
481 }
482
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
483 bool js_value_is_proxy(OurContext* MAYBE_UNUSED(context), jsval maybe_proxy)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
484 {
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
485 JSClass* klass = JS_GET_CLASS(context->js, JSVAL_TO_OBJECT(maybe_proxy));
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
486
487 return &JSLandProxyClass == klass
488 || &JSLandClassProxyClass == klass
489 || &JSLandCallableProxyClass == klass;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
490 }
491
e18f74d @jbarnette Renaming proxies for clarity.
authored
492 VALUE unwrap_js_land_proxy(OurContext* context, jsval proxy)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
493 {
01b0682 @jbarnette JS proxies roundtrip.
authored
494 VALUE value;
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
495 JSObject *proxy_object = JSVAL_TO_OBJECT(proxy);
496
97b8244 @matthewd Root everything in sight.
matthewd authored
497 value = (VALUE)JS_GetInstancePrivate(context->js, proxy_object,
498 JS_GET_CLASS(context->js, proxy_object), NULL);
109858e @jbarnette Make JSLandProxyClass more easily parameterizable.
authored
499
f0cc336 js proxies roundtrip correctly. still no gc root.
jbarnette authored
500 return value;
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
501 }
502
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
503 static void finalize(JSContext* js_context, JSObject* obj)
504 {
505 VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context);
506
507 if (ruby_context)
508 {
509 OurContext* context;
510 Data_Get_Struct(ruby_context, OurContext, context);
511
97b8244 @matthewd Root everything in sight.
matthewd authored
512 VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj,
513 JS_GET_CLASS(context->js, obj), NULL);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
514
515 // remove the proxy OID from the id map
516 JS_HashTableRemove(context->rbids, (void *)rb_obj_id(self));
517
518 // free up the ruby value for GC
c1a7fbf @matthewd Added a bunch of exception propagation handling.
matthewd authored
519 call_ruby_from_js(context, NULL, ruby_context, rb_intern("remove_gcthing"), 1, self);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
520 }
521 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
522
9149af0 @matthewd More JSBool conversions.
matthewd authored
523 JSBool make_js_land_proxy(OurContext* context, VALUE value, jsval* retval)
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
524 {
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
525 jsid id = (jsid)JS_HashTableLookup(context->rbids, (void *)rb_obj_id(value));
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
526
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
527 if (id)
528 {
9149af0 @matthewd More JSBool conversions.
matthewd authored
529 return JS_IdToValue(context->js, id, retval);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
530 }
531 else
532 {
ce00ab6 @matthewd Cautiously edge toward a slippery slope, by adding extra cleanup callbac...
matthewd authored
533 PREPARE_JROOTS(context, 1, 0);
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
534
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
535 JSObject *jsobj;
b77b3ad @jbarnette Make sure multiple proxy classes are supported.
authored
536
537 JSClass *klass = &JSLandProxyClass;
538 if (T_CLASS == TYPE(value)) klass = &JSLandClassProxyClass;
539
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
540 // FIXME: hack; should happen in Rubyland
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
541 if (T_STRUCT == TYPE(value))
542 rb_funcall(Johnson_SpiderMonkey_JSLandProxy(),
543 rb_intern("treat_all_properties_as_methods"), 1, value);
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
544
f518879 @jbarnette Any Rubyland object that responds to call can be called as a function in...
authored
545 bool callable_p = Qtrue == rb_funcall(value,
546 rb_intern("respond_to?"), 1, rb_str_new2("call"));
b7616dd @jbarnette Reimplement property and method access. Mostly.
authored
547
73ad637 @jbarnette Cleaned up proxying of callable (Proc, Method) Ruby objects.
authored
548 if (callable_p)
549 klass = &JSLandCallableProxyClass;
550
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
551 JCHECK((jsobj = JS_NewObject(context->js, klass, NULL, NULL)));
552 JROOT(jsobj);
f518879 @jbarnette Any Rubyland object that responds to call can be called as a function in...
authored
553
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
554 JCHECK(JS_SetPrivate(context->js, jsobj, (void*)value));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
555
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
556 JCHECK(JS_DefineFunction(context->js, jsobj, "__noSuchMethod__", method_missing, 2, 0));
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
557
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
558 JCHECK(JS_DefineFunction(context->js, jsobj, "toArray", to_array, 0, 0));
559 JCHECK(JS_DefineFunction(context->js, jsobj, "toString", to_string, 0, 0));
70adb2d @matthewd Enabled a bunch of warnings, and added .toString/.toArray/.to_s
matthewd authored
560
9149af0 @matthewd More JSBool conversions.
matthewd authored
561 *retval = OBJECT_TO_JSVAL(jsobj);
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
562
563 jsval newid;
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
564 JCHECK(JS_ValueToId(context->js, *retval, &newid));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
565
566 // put the proxy OID in the id map
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
567 JCHECK(JS_HashTableAdd(context->rbids, (void *)rb_obj_id(value), (void *)newid));
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
568
569 // root the ruby value for GC
570 VALUE ruby_context = (VALUE)JS_GetContextPrivate(context->js);
571 rb_funcall(ruby_context, rb_intern("add_gcthing"), 1, value);
9149af0 @matthewd More JSBool conversions.
matthewd authored
572
06cd4a9 @matthewd Use some macros to keep track of what's been rooted.
matthewd authored
573 JRETURN;
3c24fe9 Fixed Ruby value tracking/GC rooting.
jbarnette authored
574 }
69ace87 JS-land proxies for Ruby objects. No support for GC or roundtripping.
jbarnette authored
575 }
Something went wrong with that request. Please try again.