From 01b068241ff99cfb5fa604bac46ea28d9dc4c212 Mon Sep 17 00:00:00 2001 From: John Barnette Date: Mon, 31 Mar 2008 18:10:32 -0700 Subject: [PATCH] JS proxies roundtrip. --- ext/spidermonkey/conversions.c | 65 ++++++++++++---------- ext/spidermonkey/js_proxy.c | 7 ++- ext/spidermonkey/js_proxy.h | 2 +- test/johnson/spidermonkey/js_proxy_test.rb | 5 ++ 4 files changed, 45 insertions(+), 34 deletions(-) diff --git a/ext/spidermonkey/conversions.c b/ext/spidermonkey/conversions.c index 0489feb..9ca35a0 100644 --- a/ext/spidermonkey/conversions.c +++ b/ext/spidermonkey/conversions.c @@ -119,6 +119,40 @@ static JSBool jsval_is_a_symbol(OurContext* context, jsval maybe_symbol) return is_a_symbol; } +VALUE convert_object_to_ruby(OurContext* context, jsval object) +{ + if (JSVAL_NULL == object) return Qnil; + + if (jsval_is_a_symbol(context, object)) + return ID2SYM(rb_intern(JS_GetStringBytes(JS_ValueToString(context->js, object)))); + + if (js_value_is_proxy(context, object)) + return unwrap_js_proxy(context, object); + + VALUE id = (VALUE)JS_HashTableLookup(context->jsids, (void *)object); + + if (id) + { + // if we already have a proxy, return it + return rb_funcall(rb_const_get(rb_cObject, + rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, id); + } + else + { + // otherwise make one and cache it + VALUE proxy = make_ruby_proxy(context, object); + + // put the proxy OID in the id map + assert(JS_HashTableAdd(context->jsids, (void *)object, (void *)rb_obj_id(proxy))); + + // root the value for JS GC + char key[10]; + sprintf(key, "%x", (int)object); + JS_SetProperty(context->js, context->gcthings, key, &object); + + return proxy; + } +} VALUE convert_to_ruby(OurContext* context, jsval js) { @@ -129,36 +163,7 @@ VALUE convert_to_ruby(OurContext* context, jsval js) case JSTYPE_FUNCTION: case JSTYPE_OBJECT: - if (JSVAL_NULL == js) return Qnil; - - if (jsval_is_a_symbol(context, js)) - return ID2SYM(rb_intern(JS_GetStringBytes(JS_ValueToString(context->js, js)))); - - // FIXME: if it's wrapping a Ruby object, unwrap and return it - - VALUE id = (VALUE)JS_HashTableLookup(context->jsids, (void *)js); - - if (id) - { - // if we already have a proxy, return it - return rb_funcall(rb_const_get(rb_cObject, - rb_intern("ObjectSpace")), rb_intern("_id2ref"), 1, id); - } - else - { - // otherwise make one and cache it - VALUE proxy = make_ruby_proxy(context, js); - - // put the proxy OID in the id map - assert(JS_HashTableAdd(context->jsids, (void *)js, (void *)rb_obj_id(proxy))); - - // root the value for JS GC - char key[10]; - sprintf(key, "%x", (int)js); - JS_SetProperty(context->js, context->gcthings, key, &js); - - return proxy; - } + return convert_object_to_ruby(context, js); case JSTYPE_BOOLEAN: return JSVAL_TRUE == js ? Qtrue : Qfalse; diff --git a/ext/spidermonkey/js_proxy.c b/ext/spidermonkey/js_proxy.c index a4d174b..23b2dcc 100644 --- a/ext/spidermonkey/js_proxy.c +++ b/ext/spidermonkey/js_proxy.c @@ -156,14 +156,15 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j return JS_TRUE; } -JSBool js_value_is_proxy(jsval maybe_proxy) +JSBool js_value_is_proxy(OurContext* context, jsval maybe_proxy) { - return JS_FALSE; + return JS_InstanceOf(context->js, JSVAL_TO_OBJECT(maybe_proxy), &JSProxyClass, NULL); } VALUE unwrap_js_proxy(OurContext* context, jsval proxy) { - return Qnil; + VALUE value; + assert(value = (VALUE)JS_GetInstancePrivate(context->js, proxy, &JSProxyClass, NULL)); } // static jsval convert_ruby_object_to_jsval(CombinedContext* context, VALUE ruby) diff --git a/ext/spidermonkey/js_proxy.h b/ext/spidermonkey/js_proxy.h index ee77792..db0d7c2 100644 --- a/ext/spidermonkey/js_proxy.h +++ b/ext/spidermonkey/js_proxy.h @@ -4,7 +4,7 @@ #include "spidermonkey.h" #include "context.h" -JSBool js_value_is_proxy(jsval maybe_proxy); +JSBool js_value_is_proxy(OurContext* context, jsval maybe_proxy); VALUE unwrap_js_proxy(OurContext* context, jsval proxy); jsval make_js_proxy(OurContext* context, VALUE value); diff --git a/test/johnson/spidermonkey/js_proxy_test.rb b/test/johnson/spidermonkey/js_proxy_test.rb index 7f5320c..16baa82 100644 --- a/test/johnson/spidermonkey/js_proxy_test.rb +++ b/test/johnson/spidermonkey/js_proxy_test.rb @@ -54,6 +54,11 @@ def test_proxies_get_reused assert_js_equal(true, "foo === bar") end + def test_proxies_roundtrip + @context["foo"] = foo = Foo.new + assert_same(foo, @context.evaluate("foo")) + end + def test_getter_calls_0_arity_method @context["foo"] = Foo.new assert_js_equal(10, "foo.bar")