1
0
Fork 0
mirror of https://github.com/rubyjs/therubyracer synced 2023-03-27 23:21:42 -04:00

refactor value converter to be per-context.

This commit is contained in:
Charles Lowell 2010-08-28 10:46:30 -05:00
parent c22bbd9177
commit 1be713d53d
8 changed files with 163 additions and 245 deletions

View file

@ -66,6 +66,15 @@ namespace {
return Qfalse;
}
}
VALUE GetData(VALUE self) {
HandleScope scope;
return rr_v82rb(unwrap(self)->GetData());
}
VALUE SetData(VALUE self, VALUE data) {
HandleScope scope;
unwrap(self)->SetData(rr_rb2v8(data));
return Qnil;
}
}
void rr_init_cxt() {
@ -77,5 +86,7 @@ void rr_init_cxt() {
rr_define_method(ContextClass, "Enter", Enter, 0);
rr_define_method(ContextClass, "Exit", Exit, 0);
rr_define_method(ContextClass, "IsEntered", IsEntered, 0);
rr_define_method(ContextClass, "GetData", GetData, 0);
rr_define_method(ContextClass, "SetData", SetData, 1);
}

View file

@ -4,7 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
module V8
VERSION = '0.7.6.pre'
require 'v8/v8' #native glue
require 'v8/to'
require 'v8/portal'
require 'v8/context'
require 'v8/object'
require 'v8/array'

View file

@ -1,39 +1,23 @@
require 'set'
module V8
#TODO each context should get its own access rules instead of sharing them across
# contetxts
###### --cowboyd 07/07/2010
class Access
def self.[](cls)
@access ||= Access.new
@access[cls]
end
def initialize
@classes = {}
end
def [](cls)
@classes ||= {}
if ref = @classes[cls.object_id]
if ref.weakref_alive?
ref.__getobj__
else
@classes.delete(cls.object_id)
self[cls]
end
else
template(cls).tap do |t|
Access.setuptemplate(t.InstanceTemplate())
def initialize(portal)
@classes = Hash.new do |h, cls|
h[cls] = template(cls).tap do |t|
portal.setuptemplate(t.InstanceTemplate())
if cls.name && cls.name =~ /(::)?(\w+?)$/
t.SetClassName(C::String::NewSymbol("rb::" + $2))
else
t.SetClassName("Ruby")
end
@classes[cls.object_id] = WeakRef.new(t)
end
end
@impl = RubyAccess.new
end
def [](cls)
@classes[cls]
end
def template(cls)
@ -48,43 +32,8 @@ module V8
end
end
def self.rubyobject
@rubyobject ||= C::ObjectTemplate::New().tap do |t|
setuptemplate(t)
end
end
def self.setuptemplate(t)
t.SetNamedPropertyHandler(
NamedPropertyGetter,
NamedPropertySetter,
nil,
nil,
NamedPropertyEnumerator
)
t.SetIndexedPropertyHandler(
IndexedPropertyGetter,
IndexedPropertySetter,
nil,
nil,
IndexedPropertyEnumerator
)
end
end
module AccessibleMethods
def ruby
@ruby ||= RubyAccess.new
end
def access(info, retval = nil, &code)
obj = To.rb(info.This())
intercepts = true
result = Function.rubyprotect do
dontintercept = proc do
intercepts = false
end
code.call(obj, dontintercept)
end
intercepts ? (retval || result) : C::Empty
def method_missing(name, *args)
@impl.send(name, *args)
end
end
@ -166,6 +115,8 @@ module V8
obj.respond_to?(:length) ? (0..obj.length).to_a : yield
end
private
def accessible_methods(obj)
obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
ancestors = obj.class.ancestors.dup
@ -200,115 +151,4 @@ module V8
end
end
end
class NamedPropertyGetter
extend AccessibleMethods
def self.call(property, info)
access(info) do |obj, dontintercept|
ruby.get(obj, To.rb(property), &dontintercept)
end
end
end
class NamedPropertySetter
extend AccessibleMethods
def self.call(property, value, info)
access(info, value) do |obj, dontintercept|
ruby.set(obj, To.rb(property), To.rb(value), &dontintercept)
end
end
end
class NamedPropertyQuery
extend AccessibleMethods
class Attrs
def initialize
@flags = 0
end
def read_only
tap do
@flags |= V8::C::ReadOnly
end
end
def dont_enum
tap do
@flags |= V8::C::DontEnum
end
end
def dont_delete
tap do
@flags |= V8::C::DontDelete
end
end
end
def self.call(property, info)
attrs = Attrs.new
intercepts = true
access_query(To.rb(info.This()), To.rb(property), attrs) do
intercepts = false
end
intercepts ? C::Integer::New(attrs.flags) : C::Empty
end
def self.access_attributes(obj, name, attrs)
unless obj.respond_to?(name)
attrs.dont_enum
attrs.dont_delete
end
unless obj.respond_to?("name=")
attrs.read_only
end
end
end
class NamedPropertyEnumerator
extend AccessibleMethods
def self.call(info)
obj = To.rb(info.This())
methods = ruby.accessible_methods(obj)
methods.reject! {|m| m.to_s =~ /=$/}
names = V8::C::Array::New(methods.length)
methods.each_with_index do |name, i|
names.Set(i, C::String::New(name))
end
return names
end
end
class IndexedPropertyGetter
extend AccessibleMethods
def self.call(index, info)
access(info) do |obj, dontintercept|
ruby.iget(obj, index, &dontintercept)
end
end
end
class IndexedPropertySetter
extend AccessibleMethods
def self.call(index, value, info)
access(info, value) do |obj, dontintercept|
ruby.iset(obj, index, To.rb(value), &dontintercept)
end
end
end
class IndexedPropertyEnumerator
def self.call(info)
obj = To.rb(info.This())
if obj.respond_to?(:length)
C::Array::New(obj.length).tap do |indices|
for index in 0..obj.length - 1
indices.Set(index,index)
end
end
else
C::Array::New()
end
end
end
end

View file

@ -3,9 +3,9 @@ module V8
class Array < V8::Object
def each
@context.enter do
@portal.open do |to|
for i in 0..(@native.Length() - 1)
yield To.rb(@native.Get(i))
yield to.rb(@native.Get(i))
end
end
end

View file

@ -2,12 +2,13 @@ require 'stringio'
module V8
class Context
attr_reader :native, :scope
attr_reader :native, :scope, :access
def initialize(opts = {})
@to = Convert.new(self)
@to = Portal.new(self)
@access = Access.new(@to)
@native = opts[:with] ? C::Context::New(Access.rubyobject) : C::Context::New()
@native.enter do
@scope = To.rb(@native.Global())
@scope = @to.rb(@native.Global())
@native.Global().SetHiddenValue(C::String::New("TheRubyRacer::RubyObject"), C::External::New(opts[:with])) if opts[:with]
end
yield(self) if block_given?
@ -21,7 +22,7 @@ module V8
value = nil
C::TryCatch.try do |try|
@native.enter do
script = C::Script::Compile(To.v8(javascript.to_s), To.v8(filename.to_s))
script = C::Script::Compile(@to.v8(javascript.to_s), @to.v8(filename.to_s))
if try.HasCaught()
err = JSError.new(try)
else
@ -29,7 +30,7 @@ module V8
if try.HasCaught()
err = JSError.new(try)
else
value = To.rb(result)
value = @to.rb(result)
end
end
end

View file

@ -25,35 +25,35 @@ module V8
end
end
def self.rubyprotect(&blk)
To.v8(rubyprotect2(&blk))
end
def self.rubyprotect2
begin
yield
rescue Exception => e
case e
when SystemExit, NoMemoryError
raise e
else
error = V8::C::Exception::Error(V8::C::String::New(e.message))
error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
V8::C::ThrowException(error)
end
end
end
def self.rubycall(rubycode, *args, &block)
rubyprotect do
rubycode.call(*args, &block)
end
end
def self.rubysend(obj, message, *args, &block)
rubyprotect do
obj.send(message, *args, &block)
end
end
# def self.rubyprotect(&blk)
# To.v8(rubyprotect2(&blk))
# end
#
# def self.rubyprotect2
# begin
# yield
# rescue Exception => e
# case e
# when SystemExit, NoMemoryError
# raise e
# else
# error = V8::C::Exception::Error(V8::C::String::New(e.message))
# error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
# V8::C::ThrowException(error)
# end
# end
# end
#
# def self.rubycall(rubycode, *args, &block)
# rubyprotect do
# rubycode.call(*args, &block)
# end
# end
#
# def self.rubysend(obj, message, *args, &block)
# rubyprotect do
# obj.send(message, *args, &block)
# end
# end
end
end

View file

@ -3,35 +3,33 @@ module V8
class Object
include Enumerable
def initialize(native, context = nil)
@native = native
@context = context || C::Context::GetEntered()
raise ScriptError, "V8::Object.new called without an open V8 context" unless @context
def initialize(native, portal)
@native, @portal = native, portal
end
def [](key)
@context.enter do
To.rb(@native.Get(To.v8(key)))
@portal.open do |to|
to.rb(@native.Get(to.v8(key)))
end
end
def []=(key, value)
value.tap do
@context.enter do
@native.Set(To.v8(key), To.v8(value))
@portal.open do |to|
@native.Set(to.v8(key), to.v8(value))
end
end
end
def to_s
@context.enter do
To.rb(@native.ToString())
to.rb(@native.ToString())
end
end
def each
@context.enter do
for prop in To.rb(@native.GetPropertyNames())
for prop in to.rb(@native.GetPropertyNames())
yield prop, self[prop]
end
end

View file

@ -1,18 +1,26 @@
module V8
class Convert
class Portal
def initialize(context)
@named_property_getter = NamedPropertyGetter.new(self, context.access)
@named_property_setter = NamedPropertySetter.new(self, context.access)
@context = context
@named_property_getter = Interceptor(NamedPropertyGetter)
@named_property_setter = Interceptor(NamedPropertySetter)
@named_property_query = nil
@named_property_deleter = nil
@named_property_enumerator = NamedPropertyEnumerator.new(self, context.access)
@named_property_enumerator = Interceptor(NamedPropertyEnumerator)
@indexed_property_getter = IndexedPropertyGetter.new(self, context.access)
@indexed_property_setter = IndexedPropertySetter.new(self, context.access)
@indexed_property_getter = Interceptor(IndexedPropertyGetter)
@indexed_property_setter = Interceptor(IndexedPropertySetter)
@indexed_property_query = nil
@indexed_property_deleter = nil
@indexed_property_enumerator = IndexedPropertyEnumerator.new(self, context.access)
@indexed_property_enumerator = Interceptor(IndexedPropertyEnumerator)
end
def open
@context.native.enter do
yield(self)
end if block_given?
end
def rb(value)
@ -42,7 +50,7 @@ module V8
for i in 0..arguments.Length() - 1
rbargs << rb(arguments[i])
end
V8::Function.rubycall(value, *rbargs)
rubycall(value, *rbargs)
end
return template.GetFunction()
when ::Array
@ -68,30 +76,82 @@ module V8
else
args = C::Array::New(1)
args.Set(0, C::External::New(value))
obj = Access[value.class].GetFunction().NewInstance(args)
obj = @context.access[value.class].GetFunction().NewInstance(args)
return obj
end
end
################################
def rubyprotect(&blk)
self.v8(rubyprotect2(&blk))
end
def rubyprotect2
begin
yield
rescue Exception => e
case e
when SystemExit, NoMemoryError
raise e
else
error = V8::C::Exception::Error(V8::C::String::New(e.message))
error.SetHiddenValue("TheRubyRacer::Cause", C::External::New(e))
V8::C::ThrowException(error)
end
end
end
def rubycall(rubycode, *args, &block)
rubyprotect do
rubycode.call(*args, &block)
end
end
def rubysend(obj, message, *args, &block)
rubyprotect do
obj.send(message, *args, &block)
end
end
def setuptemplate(t)
t.SetNamedPropertyHandler(
@named_property_getter,
@named_property_setter,
nil,
nil,
@named_property_enumerator
)
t.SetIndexedPropertyHandler(
@indexed_property_getter,
@indexed_property_setter,
nil,
nil,
@indexed_property_enumerator
)
end
################################
private
def peer(value)
external = value.GetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyObject"))
if external && !external.IsEmpty()
external.Value()
else
yield.new(value)
yield.new(value, self)
end
end
class Interceptor
def initialize(convert, access)
@to = convert
@access = access
def initialize(portal, context)
@to = portal
@context = context
end
def intercept(info, retval = nil, &code)
obj = @to.rb(info.This())
intercepts = true
result = Function.rubyprotect do
result = @to.rubyprotect do
dontintercept = proc do
intercepts = false
end
@ -99,6 +159,14 @@ module V8
end
intercepts ? (retval || result) : C::Empty
end
def access
@context.access
end
end
def Interceptor(cls)
cls.new self, @context
end
class PropertyAttributes
@ -129,7 +197,7 @@ module V8
class NamedPropertyGetter < Interceptor
def call(property, info)
intercept(info) do |obj, dontintercept|
@access.get(obj, @to.rb(property), &dontintercept)
access.get(obj, @to.rb(property), &dontintercept)
end
end
end
@ -137,7 +205,7 @@ module V8
class NamedPropertySetter < Interceptor
def call(property, value, info)
intercept(info, value) do |obj, dontintercept|
@access.set(obj, @to.rb(property), @to.rb(value), &dontintercept)
access.set(obj, @to.rb(property), @to.rb(value), &dontintercept)
end
end
end
@ -146,7 +214,7 @@ module V8
def call(property, info)
attributes = PropertyAttributes.new
result = intercept(info) do |obj, dontintercept|
@access.query(obj, @to.rb(property), attributes, &dontintercept)
access.query(obj, @to.rb(property), attributes, &dontintercept)
end
return result == C::Empty ? result : C::Integer::New(attributes.flags)
end
@ -155,7 +223,7 @@ module V8
class NamedPropertyEnumerator < Interceptor
def call(info)
intercept(info) do |obj, dontintercept|
@access.names(obj, &dontintercept)
access.names(obj, &dontintercept)
end
end
end
@ -163,7 +231,7 @@ module V8
class NamedPropertyDeleter < Interceptor
def call(property, info)
intercept(info) do |obj, dontintercept|
@access.delete(obj, property, &dontintercept)
access.delete(obj, property, &dontintercept)
end
end
end
@ -171,7 +239,7 @@ module V8
class IndexedPropertyGetter < Interceptor
def call(index, info)
intercept(info) do |obj, dontintercept|
@access.iget(obj, index, &dontintercept)
access.iget(obj, index, &dontintercept)
end
end
end
@ -179,7 +247,7 @@ module V8
class IndexedPropertySetter < Interceptor
def call(index, value, info)
intercept(info, value) do |obj, dontintercept|
@access.iset(obj, index, @to.rb(value), &dontintercept)
access.iset(obj, index, @to.rb(value), &dontintercept)
end
end
end
@ -188,7 +256,7 @@ module V8
def call(property, info)
attributes = PropertyAttributes.new
result = intercept(info) do |obj, dontintercept|
@access.indices(obj, &dontintercept)
access.indices(obj, &dontintercept)
end
result == C::Empty ? C::Empty : C::Integer::New(attributes.flags)
end
@ -197,7 +265,7 @@ module V8
class IndexedPropertyDeleter < Interceptor
def call(index, info)
intercept(info) do |obj, dontintercept|
@access.idelete(obj, index, &dontintercept)
access.idelete(obj, index, &dontintercept)
end
end
end
@ -205,7 +273,7 @@ module V8
class IndexedPropertyEnumerator < Interceptor
def call(info)
intercept(info) do |obj, dontintercept|
@access.indices(obj, &dontintercept)
access.indices(obj, &dontintercept)
end
end
end