Skip to content
This repository has been archived by the owner on Aug 18, 2018. It is now read-only.

Commit

Permalink
JS proxies roundtrip.
Browse files Browse the repository at this point in the history
  • Loading branch information
jbarnette committed Apr 1, 2008
1 parent fd40f93 commit 01b0682
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 34 deletions.
65 changes: 35 additions & 30 deletions ext/spidermonkey/conversions.c
Expand Up @@ -119,6 +119,40 @@ static JSBool jsval_is_a_symbol(OurContext* context, jsval maybe_symbol)
return is_a_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) VALUE convert_to_ruby(OurContext* context, jsval js)
{ {
Expand All @@ -129,36 +163,7 @@ VALUE convert_to_ruby(OurContext* context, jsval js)


case JSTYPE_FUNCTION: case JSTYPE_FUNCTION:
case JSTYPE_OBJECT: case JSTYPE_OBJECT:
if (JSVAL_NULL == js) return Qnil; return convert_object_to_ruby(context, js);

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;
}


case JSTYPE_BOOLEAN: case JSTYPE_BOOLEAN:
return JSVAL_TRUE == js ? Qtrue : Qfalse; return JSVAL_TRUE == js ? Qtrue : Qfalse;
Expand Down
7 changes: 4 additions & 3 deletions ext/spidermonkey/js_proxy.c
Expand Up @@ -156,14 +156,15 @@ static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, j
return JS_TRUE; 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) 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) // static jsval convert_ruby_object_to_jsval(CombinedContext* context, VALUE ruby)
Expand Down
2 changes: 1 addition & 1 deletion ext/spidermonkey/js_proxy.h
Expand Up @@ -4,7 +4,7 @@
#include "spidermonkey.h" #include "spidermonkey.h"
#include "context.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); VALUE unwrap_js_proxy(OurContext* context, jsval proxy);
jsval make_js_proxy(OurContext* context, VALUE value); jsval make_js_proxy(OurContext* context, VALUE value);


Expand Down
5 changes: 5 additions & 0 deletions test/johnson/spidermonkey/js_proxy_test.rb
Expand Up @@ -54,6 +54,11 @@ def test_proxies_get_reused
assert_js_equal(true, "foo === bar") assert_js_equal(true, "foo === bar")
end end


def test_proxies_roundtrip
@context["foo"] = foo = Foo.new
assert_same(foo, @context.evaluate("foo"))
end

def test_getter_calls_0_arity_method def test_getter_calls_0_arity_method
@context["foo"] = Foo.new @context["foo"] = Foo.new
assert_js_equal(10, "foo.bar") assert_js_equal(10, "foo.bar")
Expand Down

0 comments on commit 01b0682

Please sign in to comment.