diff --git a/ext/v8/v8_callbacks.cpp b/ext/v8/v8_callbacks.cpp index ddfbe9e..1fd6e3c 100644 --- a/ext/v8/v8_callbacks.cpp +++ b/ext/v8/v8_callbacks.cpp @@ -86,7 +86,7 @@ namespace { return rr_v82rb(args(self)->isConstructCall); } VALUE _Data(VALUE self) { - return rr_v82rb(info(self)->data); + return rb_iv_get(self, "data"); } struct WrapAccessorInfo : Wrap { diff --git a/ext/v8/v8_template.cpp b/ext/v8/v8_template.cpp index d97ba29..c7b4658 100644 --- a/ext/v8/v8_template.cpp +++ b/ext/v8/v8_template.cpp @@ -39,10 +39,17 @@ namespace { } Handle 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 result = rb_funcall(code, rb_intern("call"), 1, rb_args); - return rr_rb2v8(result); + rb_iv_set(rb_args, "data", data); + if (RTEST(handler)) { + VALUE result = rb_funcall(handler, rb_intern("call"), 1, rb_args); + return rr_rb2v8(result); + } else { + return Handle(); + } } namespace Obj { @@ -259,26 +266,25 @@ namespace { namespace Func { - VALUE New(VALUE function_template) { - HandleScope handles; - VALUE code = rb_block_proc(); - if (NIL_P(code)) { - return Qnil; - } - Local templ = FunctionTemplate::New(RubyInvocationCallback, rr_v8_external_create(code)); - 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; + Handle make_v8_data(int argc, VALUE *argv, const char* argf) { + VALUE handler; VALUE data; + rb_scan_args(argc, argv, argf, &handler, &data); + VALUE v8_data = rb_hash_new(); + rb_hash_aset(v8_data, "handler", handler); + rb_hash_aset(v8_data, "data", data); + return rr_v8_external_create(v8_data); } - VALUE SetCallHandler(VALUE self) { - HandleScope handles; - VALUE code = rb_block_proc(); - if (NIL_P(code)) { - return Qnil; - } - func(self)->SetCallHandler(RubyInvocationCallback, rr_v8_external_create(code)); + + VALUE New(int argc, VALUE *argv, VALUE self) { + HandleScope h; + Handle v8_data = make_v8_data(argc, argv, "02"); + Local t = FunctionTemplate::New(RubyInvocationCallback, v8_data); + return rr_v8_handle_new(self,t); + } + VALUE SetCallHandler(int argc, VALUE *argv, VALUE self) { + HandleScope h; + Handle v8_data = make_v8_data(argc, argv, "11"); + func(self)->SetCallHandler(RubyInvocationCallback, v8_data); return Qnil; } VALUE PrototypeTemplate(VALUE self) { @@ -322,8 +328,8 @@ void rr_init_template() { rr_define_method(ObjectTemplateClass, "SetCallAsFunctionHandler", Obj::SetCallAsFunctionHandler, 0); FunctionTemplateClass = rr_define_class("FunctionTemplate", Template); - rr_define_singleton_method(FunctionTemplateClass, "New", Func::New, 0); - rr_define_method(FunctionTemplateClass, "SetCallHandler", Func::SetCallHandler, 0); + rr_define_singleton_method(FunctionTemplateClass, "New", Func::New, -1); + rr_define_method(FunctionTemplateClass, "SetCallHandler", Func::SetCallHandler, -1); rr_define_method(FunctionTemplateClass, "PrototypeTemplate", Func::PrototypeTemplate, 0); rr_define_method(FunctionTemplateClass, "InstanceTemplate", Func::InstanceTemplate, 0); rr_define_method(FunctionTemplateClass, "Inherit", Func::Inherit, 1); diff --git a/lib/v8/context.rb b/lib/v8/context.rb index 4a4cd13..a07a744 100644 --- a/lib/v8/context.rb +++ b/lib/v8/context.rb @@ -11,7 +11,7 @@ module V8 constructor = nil template = if with constructor = @to.js_constructor_for(with.class) - constructor.SetCallHandler(&method(:tmp)) + constructor.SetCallHandler(method(:tmp)) template = constructor.InstanceTemplate() else C::ObjectTemplate::New() @@ -20,13 +20,14 @@ module V8 @native.enter do @global = @native.Global() @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) @global.SetHiddenValue(C::String::NewSymbol("TheRubyRacer::RubyContext"), C::External::New(self)) end yield(self) if block_given? end + #TODO: get rid of this. def tmp(arguments) return arguments.This() end diff --git a/lib/v8/portal.rb b/lib/v8/portal.rb index f157945..23c4db1 100644 --- a/lib/v8/portal.rb +++ b/lib/v8/portal.rb @@ -28,13 +28,16 @@ module V8 for i in 0..arguments.Length() - 1 rbargs << rb(arguments[i]) end + cls = arguments.Data() instance = rubysend(cls, :new, *rbargs) end @proxies.register_javascript_proxy arguments.This(), :for => instance + rescue StandardError => e + warn e end 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()) if cls != ::Object && cls.superclass != ::Object && cls.superclass != ::Class template.Inherit(js_constructor_for(cls.superclass)) @@ -52,11 +55,11 @@ module V8 constructor = js_constructor_for(ruby_class) function = constructor.GetFunction() 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 prototype = rubytemplate.NewInstance() #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) def constructor.embedded?;true;end end diff --git a/lib/v8/portal/functions.rb b/lib/v8/portal/functions.rb index 1119f37..acf2105 100644 --- a/lib/v8/portal/functions.rb +++ b/lib/v8/portal/functions.rb @@ -11,35 +11,43 @@ module V8 end def Proc(p) + #TODO: check this for memory leaks @procs[p] ||= begin - template = C::FunctionTemplate::New() do |arguments| - rbargs = [] - for i in 0..arguments.Length() - 1 - rbargs << @portal.rb(arguments[i]) - end - @portal.rubycall(p, *rbargs) - end + template = C::FunctionTemplate::New(method(:callproc), p) template.GetFunction() end end def UnboundMethod(method) + #TODO: check this for memory leaks. @methods[method.to_s] ||= begin - template = C::FunctionTemplate::New() do |arguments| - 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 = C::FunctionTemplate::New(method(:callmethod), method) template.GetFunction() end end 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 \ No newline at end of file