mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
support two-way identity mapping
This commit is contained in:
parent
6dbd647680
commit
6157d35d4a
5 changed files with 78 additions and 16 deletions
|
@ -2,11 +2,18 @@
|
||||||
|
|
||||||
namespace rr {
|
namespace rr {
|
||||||
void Template::Init() {
|
void Template::Init() {
|
||||||
ClassBuilder("Template");
|
ClassBuilder("Template").
|
||||||
|
defineMethod("Set", &Set);
|
||||||
ObjectTemplate::Init();
|
ObjectTemplate::Init();
|
||||||
FunctionTemplate::Init();
|
FunctionTemplate::Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE Template::Set(int argc, VALUE argv[], VALUE self) {
|
||||||
|
VALUE name; VALUE value; VALUE attributes;
|
||||||
|
rb_scan_args(argc, argv, "21", &name, &value, &attributes);
|
||||||
|
Void(Template(self)->Set(*String(name), *Value(value), PropertyAttribute(attributes)));
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectTemplate::Init() {
|
void ObjectTemplate::Init() {
|
||||||
ClassBuilder("ObjectTemplate", "Template").
|
ClassBuilder("ObjectTemplate", "Template").
|
||||||
defineSingletonMethod("New", &New).
|
defineSingletonMethod("New", &New).
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module V8
|
module V8
|
||||||
class Context
|
class Context
|
||||||
attr_reader :native
|
attr_reader :native, :conversion
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@native = V8::C::Context::New()
|
@native = V8::C::Context::New()
|
||||||
|
@ -15,6 +15,14 @@ module V8
|
||||||
@conversion.to_v8(ruby_object)
|
@conversion.to_v8(ruby_object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def link(ruby_object, v8_object)
|
||||||
|
@conversion.equate ruby_object, v8_object
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.link(*args)
|
||||||
|
current.link *args
|
||||||
|
end
|
||||||
|
|
||||||
def enter(&block)
|
def enter(&block)
|
||||||
if !entered?
|
if !entered?
|
||||||
lock_scope_and_enter(&block)
|
lock_scope_and_enter(&block)
|
||||||
|
|
|
@ -1,30 +1,57 @@
|
||||||
class V8::Conversion
|
class V8::Conversion
|
||||||
module Identity
|
module Identity
|
||||||
def to_ruby(v8_object)
|
def to_ruby(v8_object)
|
||||||
v8_idmap.lookup(v8_object) {super}
|
v8_idmap[v8_object] || super
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_v8(ruby_object)
|
||||||
|
rb_idmap[ruby_object] || super
|
||||||
|
end
|
||||||
|
|
||||||
|
def equate(ruby_object, v8_object)
|
||||||
|
v8_idmap.equate(v8_object, ruby_object)
|
||||||
|
rb_idmap.equate(ruby_object, v8_object)
|
||||||
end
|
end
|
||||||
|
|
||||||
def v8_idmap
|
def v8_idmap
|
||||||
@v8_idmap ||= V8IDMap.new
|
@v8_idmap ||= V8IDMap.new
|
||||||
end
|
end
|
||||||
|
|
||||||
class V8IDMap
|
def rb_idmap
|
||||||
|
@ruby_idmap ||= RubyIDMap.new
|
||||||
|
end
|
||||||
|
|
||||||
|
class IDMap
|
||||||
def initialize
|
def initialize
|
||||||
@storage = {}
|
@map = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def lookup(v8_object)
|
def [](object)
|
||||||
if v8_object.is_a?(V8::C::Object)
|
weakref = @map[to_key(object)]
|
||||||
weakref = @storage[v8_object.GetIdentityHash()]
|
if weakref && weakref.weakref_alive?
|
||||||
if weakref && weakref.weakref_alive?
|
weakref.__getobj__
|
||||||
weakref.__getobj__
|
|
||||||
else
|
|
||||||
@storage[v8_object.GetIdentityHash()] = WeakRef.new(yield)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
yield
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def equate(key_object, value_object)
|
||||||
|
@map[to_key(key_object)] = WeakRef.new(value_object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RubyIDMap < IDMap
|
||||||
|
def to_key(object)
|
||||||
|
object.object_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class V8IDMap < IDMap
|
||||||
|
def to_key(object)
|
||||||
|
object.GetIdentityHash()
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](v8_object)
|
||||||
|
super if v8_object.is_a?(V8::C::Object)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,12 +1,31 @@
|
||||||
class V8::Conversion
|
class V8::Conversion
|
||||||
module Object
|
module Object
|
||||||
def to_v8
|
def to_v8
|
||||||
V8::C::Object::New()
|
template = V8::C::ObjectTemplate::New()
|
||||||
|
template.SetNamedPropertyHandler(Get, nil, nil, nil, nil, V8::C::External::New(self))
|
||||||
|
instance = template.NewInstance()
|
||||||
|
V8::Context.link self, instance
|
||||||
|
return instance
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_ruby
|
def to_ruby
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Get
|
||||||
|
def self.call(property, info)
|
||||||
|
context = V8::Context.current
|
||||||
|
object = info.Data().Value()
|
||||||
|
name = property.Utf8Value()
|
||||||
|
if object.respond_to?(name) && object.method(name).arity <= 0
|
||||||
|
context.to_v8 object.send(name)
|
||||||
|
else
|
||||||
|
V8::C::Value::Empty
|
||||||
|
end
|
||||||
|
rescue Exception => e
|
||||||
|
warn "uncaught exception: #{e.class}: #{e.message} while accessing object property: #{e.backtrace.join('\n')}"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
module NativeObject
|
module NativeObject
|
||||||
|
|
|
@ -6,6 +6,7 @@ class V8::Object
|
||||||
def initialize(native = nil)
|
def initialize(native = nil)
|
||||||
@context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context"
|
@context = V8::Context.current or fail "tried to initialize a #{self.class} without being in an entered V8::Context"
|
||||||
@native = native || V8::C::Object::New()
|
@native = native || V8::C::Object::New()
|
||||||
|
@context.link self, @native
|
||||||
end
|
end
|
||||||
|
|
||||||
def [](key)
|
def [](key)
|
||||||
|
|
Loading…
Reference in a new issue