mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
bring low-level function template callbacks more in line with the way V8 does it.
This commit is contained in:
parent
5c2c4b0b85
commit
707973b3e5
5 changed files with 65 additions and 47 deletions
|
@ -86,7 +86,7 @@ namespace {
|
||||||
return rr_v82rb(args(self)->isConstructCall);
|
return rr_v82rb(args(self)->isConstructCall);
|
||||||
}
|
}
|
||||||
VALUE _Data(VALUE self) {
|
VALUE _Data(VALUE self) {
|
||||||
return rr_v82rb(info(self)->data);
|
return rb_iv_get(self, "data");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WrapAccessorInfo : Wrap {
|
struct WrapAccessorInfo : Wrap {
|
||||||
|
|
|
@ -39,10 +39,17 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle<Value> RubyInvocationCallback(const Arguments& args) {
|
Handle<Value> RubyInvocationCallback(const Arguments& args) {
|
||||||
VALUE code = (VALUE)External::Unwrap(args.Data());
|
VALUE v8_data = (VALUE)External::Unwrap(args.Data());
|
||||||
|
VALUE handler = rb_hash_lookup(v8_data, "handler");
|
||||||
|
VALUE data = rb_hash_lookup(v8_data, "data");
|
||||||
VALUE rb_args = rr_v82rb(args);
|
VALUE rb_args = rr_v82rb(args);
|
||||||
VALUE result = rb_funcall(code, rb_intern("call"), 1, rb_args);
|
rb_iv_set(rb_args, "data", data);
|
||||||
return rr_rb2v8(result);
|
if (RTEST(handler)) {
|
||||||
|
VALUE result = rb_funcall(handler, rb_intern("call"), 1, rb_args);
|
||||||
|
return rr_rb2v8(result);
|
||||||
|
} else {
|
||||||
|
return Handle<Value>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Obj {
|
namespace Obj {
|
||||||
|
@ -259,26 +266,25 @@ namespace {
|
||||||
|
|
||||||
namespace Func {
|
namespace Func {
|
||||||
|
|
||||||
VALUE New(VALUE function_template) {
|
Handle<Value> make_v8_data(int argc, VALUE *argv, const char* argf) {
|
||||||
HandleScope handles;
|
VALUE handler; VALUE data;
|
||||||
VALUE code = rb_block_proc();
|
rb_scan_args(argc, argv, argf, &handler, &data);
|
||||||
if (NIL_P(code)) {
|
VALUE v8_data = rb_hash_new();
|
||||||
return Qnil;
|
rb_hash_aset(v8_data, "handler", handler);
|
||||||
}
|
rb_hash_aset(v8_data, "data", data);
|
||||||
Local<FunctionTemplate> templ = FunctionTemplate::New(RubyInvocationCallback, rr_v8_external_create(code));
|
return rr_v8_external_create(v8_data);
|
||||||
VALUE ref = rr_v8_handle_new(function_template,templ);
|
|
||||||
|
|
||||||
//TODO: make sure that this reference is retained, if necessary.
|
|
||||||
// rr_v8_ref_setref(ref, "code", code);
|
|
||||||
return ref;
|
|
||||||
}
|
}
|
||||||
VALUE SetCallHandler(VALUE self) {
|
|
||||||
HandleScope handles;
|
VALUE New(int argc, VALUE *argv, VALUE self) {
|
||||||
VALUE code = rb_block_proc();
|
HandleScope h;
|
||||||
if (NIL_P(code)) {
|
Handle<Value> v8_data = make_v8_data(argc, argv, "02");
|
||||||
return Qnil;
|
Local<FunctionTemplate> t = FunctionTemplate::New(RubyInvocationCallback, v8_data);
|
||||||
}
|
return rr_v8_handle_new(self,t);
|
||||||
func(self)->SetCallHandler(RubyInvocationCallback, rr_v8_external_create(code));
|
}
|
||||||
|
VALUE SetCallHandler(int argc, VALUE *argv, VALUE self) {
|
||||||
|
HandleScope h;
|
||||||
|
Handle<Value> v8_data = make_v8_data(argc, argv, "11");
|
||||||
|
func(self)->SetCallHandler(RubyInvocationCallback, v8_data);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
VALUE PrototypeTemplate(VALUE self) {
|
VALUE PrototypeTemplate(VALUE self) {
|
||||||
|
@ -322,8 +328,8 @@ void rr_init_template() {
|
||||||
rr_define_method(ObjectTemplateClass, "SetCallAsFunctionHandler", Obj::SetCallAsFunctionHandler, 0);
|
rr_define_method(ObjectTemplateClass, "SetCallAsFunctionHandler", Obj::SetCallAsFunctionHandler, 0);
|
||||||
|
|
||||||
FunctionTemplateClass = rr_define_class("FunctionTemplate", Template);
|
FunctionTemplateClass = rr_define_class("FunctionTemplate", Template);
|
||||||
rr_define_singleton_method(FunctionTemplateClass, "New", Func::New, 0);
|
rr_define_singleton_method(FunctionTemplateClass, "New", Func::New, -1);
|
||||||
rr_define_method(FunctionTemplateClass, "SetCallHandler", Func::SetCallHandler, 0);
|
rr_define_method(FunctionTemplateClass, "SetCallHandler", Func::SetCallHandler, -1);
|
||||||
rr_define_method(FunctionTemplateClass, "PrototypeTemplate", Func::PrototypeTemplate, 0);
|
rr_define_method(FunctionTemplateClass, "PrototypeTemplate", Func::PrototypeTemplate, 0);
|
||||||
rr_define_method(FunctionTemplateClass, "InstanceTemplate", Func::InstanceTemplate, 0);
|
rr_define_method(FunctionTemplateClass, "InstanceTemplate", Func::InstanceTemplate, 0);
|
||||||
rr_define_method(FunctionTemplateClass, "Inherit", Func::Inherit, 1);
|
rr_define_method(FunctionTemplateClass, "Inherit", Func::Inherit, 1);
|
||||||
|
|
|
@ -11,7 +11,7 @@ module V8
|
||||||
constructor = nil
|
constructor = nil
|
||||||
template = if with
|
template = if with
|
||||||
constructor = @to.js_constructor_for(with.class)
|
constructor = @to.js_constructor_for(with.class)
|
||||||
constructor.SetCallHandler(&method(:tmp))
|
constructor.SetCallHandler(method(:tmp))
|
||||||
template = constructor.InstanceTemplate()
|
template = constructor.InstanceTemplate()
|
||||||
else
|
else
|
||||||
C::ObjectTemplate::New()
|
C::ObjectTemplate::New()
|
||||||
|
@ -20,13 +20,14 @@ module V8
|
||||||
@native.enter do
|
@native.enter do
|
||||||
@global = @native.Global()
|
@global = @native.Global()
|
||||||
@to.proxies.register_javascript_proxy @global, :for => with if with
|
@to.proxies.register_javascript_proxy @global, :for => with if with
|
||||||
constructor.SetCallHandler(&@to.method(:invoke_non_callable_constructor)) if constructor
|
constructor.SetCallHandler(@to.method(:invoke_non_callable_constructor)) if constructor
|
||||||
@scope = @to.rb(@global)
|
@scope = @to.rb(@global)
|
||||||
@global.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyContext"), C::External::New(self))
|
@global.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyContext"), C::External::New(self))
|
||||||
end
|
end
|
||||||
yield(self) if block_given?
|
yield(self) if block_given?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
#TODO: get rid of this.
|
||||||
def tmp(arguments)
|
def tmp(arguments)
|
||||||
return arguments.This()
|
return arguments.This()
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,13 +28,16 @@ module V8
|
||||||
for i in 0..arguments.Length() - 1
|
for i in 0..arguments.Length() - 1
|
||||||
rbargs << rb(arguments[i])
|
rbargs << rb(arguments[i])
|
||||||
end
|
end
|
||||||
|
cls = arguments.Data()
|
||||||
instance = rubysend(cls, :new, *rbargs)
|
instance = rubysend(cls, :new, *rbargs)
|
||||||
end
|
end
|
||||||
@proxies.register_javascript_proxy arguments.This(), :for => instance
|
@proxies.register_javascript_proxy arguments.This(), :for => instance
|
||||||
|
rescue StandardError => e
|
||||||
|
warn e
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_js_constructor(cls)
|
def make_js_constructor(cls)
|
||||||
template = C::FunctionTemplate::New(&method(:invoke_non_callable_constructor))
|
template = C::FunctionTemplate::New(method(:invoke_non_callable_constructor))
|
||||||
setuptemplate(template.InstanceTemplate())
|
setuptemplate(template.InstanceTemplate())
|
||||||
if cls != ::Object && cls.superclass != ::Object && cls.superclass != ::Class
|
if cls != ::Object && cls.superclass != ::Object && cls.superclass != ::Class
|
||||||
template.Inherit(js_constructor_for(cls.superclass))
|
template.Inherit(js_constructor_for(cls.superclass))
|
||||||
|
@ -52,11 +55,11 @@ module V8
|
||||||
constructor = js_constructor_for(ruby_class)
|
constructor = js_constructor_for(ruby_class)
|
||||||
function = constructor.GetFunction()
|
function = constructor.GetFunction()
|
||||||
unless constructor.respond_to?(:embedded)
|
unless constructor.respond_to?(:embedded)
|
||||||
constructor.SetCallHandler(&method(:invoke_callable_constructor))
|
constructor.SetCallHandler(method(:invoke_callable_constructor), ruby_class)
|
||||||
#create a prototype so that this constructor also acts like a ruby object
|
#create a prototype so that this constructor also acts like a ruby object
|
||||||
prototype = rubytemplate.NewInstance()
|
prototype = rubytemplate.NewInstance()
|
||||||
#set *that* object's prototype to an empty function so that it will look and behave like a function.
|
#set *that* object's prototype to an empty function so that it will look and behave like a function.
|
||||||
prototype.SetPrototype(C::FunctionTemplate::New() {}.GetFunction())
|
prototype.SetPrototype(C::FunctionTemplate::New().GetFunction())
|
||||||
function.SetPrototype(prototype)
|
function.SetPrototype(prototype)
|
||||||
def constructor.embedded?;true;end
|
def constructor.embedded?;true;end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,35 +11,43 @@ module V8
|
||||||
end
|
end
|
||||||
|
|
||||||
def Proc(p)
|
def Proc(p)
|
||||||
|
#TODO: check this for memory leaks
|
||||||
@procs[p] ||= begin
|
@procs[p] ||= begin
|
||||||
template = C::FunctionTemplate::New() do |arguments|
|
template = C::FunctionTemplate::New(method(:callproc), p)
|
||||||
rbargs = []
|
|
||||||
for i in 0..arguments.Length() - 1
|
|
||||||
rbargs << @portal.rb(arguments[i])
|
|
||||||
end
|
|
||||||
@portal.rubycall(p, *rbargs)
|
|
||||||
end
|
|
||||||
template.GetFunction()
|
template.GetFunction()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def UnboundMethod(method)
|
def UnboundMethod(method)
|
||||||
|
#TODO: check this for memory leaks.
|
||||||
@methods[method.to_s] ||= begin
|
@methods[method.to_s] ||= begin
|
||||||
template = C::FunctionTemplate::New() do |arguments|
|
template = C::FunctionTemplate::New(method(:callmethod), method)
|
||||||
rbargs = []
|
|
||||||
for i in 0..arguments.Length() - 1
|
|
||||||
rbargs << @portal.rb(arguments[i])
|
|
||||||
end
|
|
||||||
this = @portal.rb(arguments.This())
|
|
||||||
@portal.rubyprotect do
|
|
||||||
method.bind(this).call(*rbargs)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
template.GetFunction()
|
template.GetFunction()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :Method, :Proc
|
alias_method :Method, :Proc
|
||||||
|
|
||||||
|
def callproc(arguments)
|
||||||
|
proc = arguments.Data()
|
||||||
|
rbargs = []
|
||||||
|
for i in 0..arguments.Length() - 1
|
||||||
|
rbargs << @portal.rb(arguments[i])
|
||||||
|
end
|
||||||
|
@portal.rubycall(proc, *rbargs)
|
||||||
|
end
|
||||||
|
|
||||||
|
def callmethod(arguments)
|
||||||
|
method = arguments.Data()
|
||||||
|
rbargs = []
|
||||||
|
for i in 0..arguments.Length() - 1
|
||||||
|
rbargs << @portal.rb(arguments[i])
|
||||||
|
end
|
||||||
|
this = @portal.rb(arguments.This())
|
||||||
|
@portal.rubyprotect do
|
||||||
|
method.bind(this).call(*rbargs)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
Loading…
Add table
Add a link
Reference in a new issue