Permalink
Browse files

js proxies roundtrip correctly. still no gc root.

git-svn-id: svn+ssh://rubyforge.org/var/svn/johnson/trunk@112 54575175-8111-4fdf-a583-07ff49f40e23
  • Loading branch information...
2 parents fc1a3e8 + 01b0682 commit f0cc33633d5f970b3310d946b9b1a159dd127465 jbarnette committed Apr 1, 2008
@@ -89,7 +89,8 @@ static void deallocate(OurContext* context)
JS_SetContextPrivate(context->js, 0);
assert(JS_RemoveRoot(context->js, &(context->gcthings)));
- JS_HashTableDestroy(context->ids);
+ JS_HashTableDestroy(context->rbids);
+ JS_HashTableDestroy(context->jsids);
JS_DestroyContext(context->js);
JS_DestroyRuntime(context->runtime);
@@ -104,7 +105,8 @@ static VALUE allocate(VALUE klass)
assert(context->runtime = JS_NewRuntime(0x100000));
assert(context->js = JS_NewContext(context->runtime, 8192));
- assert(context->ids = new_idhash());
+ assert(context->jsids = create_id_hash());
+ assert(context->rbids = create_id_hash());
assert(context->gcthings = JS_NewObject(context->js, NULL, 0, 0));
assert(context->global = JS_NewObject(context->js, &OurGlobalClass, NULL, NULL));
@@ -10,7 +10,8 @@ typedef struct {
JSObject *global;
JSRuntime *runtime;
- JSHashTable *ids;
+ JSHashTable *jsids; // jsid -> rbid
+ JSHashTable *rbids; // rbid -> jsid
JSObject *gcthings;
jsval ex; // an exception value
@@ -27,7 +27,30 @@ static jsval convert_symbol_to_js(OurContext* context, VALUE symbol)
static jsval convert_object_to_js(OurContext* context, VALUE object)
{
- return make_js_proxy(context, object);
+ jsid id = (jsid)JS_HashTableLookup(context->rbids, (void *)rb_obj_id(object));
+
+ if (id)
+ {
+ // if we already have a proxy, return it
+ jsval js;
+ assert(JS_IdToValue(context->js, id, &js));
+ return js;
+ }
+ else
+ {
+ // otherwise make one and cache it
+ jsval proxy = make_js_proxy(context, object);
+
+ jsval newid;
+ assert(JS_ValueToId(context->js, proxy, &newid));
+
+ // put the proxy OID in the id map
+ assert(JS_HashTableAdd(context->rbids, (void *)rb_obj_id(object), (void *)newid));
+
+ // FIXME: root for GC
+
+ return proxy;
+ }
}
jsval convert_to_js(OurContext* context, VALUE ruby)
@@ -58,7 +81,6 @@ jsval convert_to_js(OurContext* context, VALUE ruby)
case T_CLASS:
case T_OBJECT:
- // FIXME: if it's a wrapped JS object, return it
return convert_object_to_js(context, ruby);
case T_DATA: // keep T_DATA last for fall-through
@@ -97,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)
{
@@ -107,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->ids, (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->ids, (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;
View
@@ -2,21 +2,15 @@
static JSHashNumber key_hash(const void *key)
{
- // just use the jsid
return (JSHashNumber)key;
}
-static intN key_comparator(const void *v1, const void *v2)
+static intN comparator(const void *v1, const void *v2)
{
- return (jsid)v1 == (jsid)v2;
+ return v1 == v2;
}
-static intN value_comparator(const void* v1, const void* v2)
+JSHashTable* create_id_hash()
{
- return (VALUE)v1 == (VALUE)v2;
-}
-
-JSHashTable * new_idhash()
-{
- return JS_NewHashTable(0, key_hash, key_comparator, value_comparator, NULL, NULL);
+ return JS_NewHashTable(0, key_hash, comparator, comparator, NULL, NULL);
}
@@ -3,6 +3,6 @@
#include "spidermonkey.h"
-JSHashTable * new_idhash();
+JSHashTable* create_id_hash();
#endif
@@ -156,14 +156,16 @@ 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));
+ return value;
}
// static jsval convert_ruby_object_to_jsval(CombinedContext* context, VALUE ruby)
@@ -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);
@@ -226,7 +226,7 @@ static void deallocate(OurRubyProxy* proxy)
if (proxy->context)
{
// remove this proxy from the OID map
- JS_HashTableRemove(proxy->context->ids, (void *)proxy->value);
+ JS_HashTableRemove(proxy->context->jsids, (void *)proxy->value);
// remove our GC handle on the JS value
char key[10];
@@ -49,6 +49,16 @@ def setup
@context.evaluate(Johnson::PRELUDE)
end
+ def test_proxies_get_reused
+ @context["foo"] = @context["bar"] = Foo.new
+ 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")

0 comments on commit f0cc336

Please sign in to comment.