diff --git a/v8js_class.cc b/v8js_class.cc index 3c25442..ae032ac 100644 --- a/v8js_class.cc +++ b/v8js_class.cc @@ -109,6 +109,20 @@ static void v8js_free_storage(void *object TSRMLS_DC) /* {{{ */ c->global_template.Reset(); c->global_template.~Persistent(); + /* Clear persistent call_impl & method_tmpls templates */ + for (std::map::iterator it = c->call_impls.begin(); + it != c->call_impls.end(); ++it) { + // No need to free it->first, as it is stored in c->template_cache and freed below + it->second.Reset(); + } + c->call_impls.~map(); + + for (std::map::iterator it = c->method_tmpls.begin(); + it != c->method_tmpls.end(); ++it) { + it->second.Reset(); + } + c->method_tmpls.~map(); + /* Clear persistent handles in template cache */ for (std::map::iterator it = c->template_cache.begin(); it != c->template_cache.end(); ++it) { @@ -217,6 +231,8 @@ static zend_object_value v8js_new(zend_class_entry *ce TSRMLS_DC) /* {{{ */ new(&c->weak_closures) std::map(); new(&c->weak_objects) std::map(); + new(&c->call_impls) std::map(); + new(&c->method_tmpls) std::map(); new(&c->v8js_v8objects) std::list(); new(&c->script_objects) std::vector(); diff --git a/v8js_class.h b/v8js_class.h index 43268bb..5880cda 100644 --- a/v8js_class.h +++ b/v8js_class.h @@ -55,6 +55,8 @@ struct v8js_ctx { std::map weak_objects; std::map weak_closures; + std::map call_impls; + std::map method_tmpls; std::list v8js_v8objects; diff --git a/v8js_object_export.cc b/v8js_object_export.cc index e108740..21b1637 100644 --- a/v8js_object_export.cc +++ b/v8js_object_export.cc @@ -518,6 +518,7 @@ template inline v8::Local v8js_named_property_callback(v8::Local property, const v8::PropertyCallbackInfo &info, property_op_t callback_type, v8::Local set_value) /* {{{ */ { v8::Isolate *isolate = info.GetIsolate(); + v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0); v8::String::Utf8Value cstr(property); const char *name = ToCString(cstr); uint name_len = strlen(name); @@ -535,9 +536,8 @@ inline v8::Local v8js_named_property_callback(v8::Local p zval *php_value; zval *object = reinterpret_cast(v8::External::Cast(*self->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY)))->Value()); - v8::Local tmpl = - v8::Local::New - (isolate, *reinterpret_cast(self->GetAlignedPointerFromInternalField(0))); + v8js_tmpl_t *tmpl_ptr = reinterpret_cast(self->GetAlignedPointerFromInternalField(0)); + v8::Local tmpl = v8::Local::New(isolate, *tmpl_ptr); ce = scope = Z_OBJCE_P(object); /* First, check the (case-insensitive) method table */ @@ -568,14 +568,35 @@ inline v8::Local v8js_named_property_callback(v8::Local p // Fake __call implementation // (only use this if method_ptr==NULL, which means // there is no actual PHP __call() implementation) - v8::Local cb = - v8::FunctionTemplate::New(isolate, - v8js_fake_call_impl, V8JS_NULL, - v8::Signature::New(isolate, tmpl))->GetFunction(); + v8::Local ft; + try { + ft = v8::Local::New + (isolate, ctx->call_impls.at(tmpl_ptr)); + } + catch (const std::out_of_range &) { + ft = v8::FunctionTemplate::New(isolate, + v8js_fake_call_impl, V8JS_NULL, + v8::Signature::New(isolate, tmpl)); + v8js_tmpl_t *persistent_ft = &ctx->call_impls[tmpl_ptr]; + persistent_ft->Reset(isolate, ft); + } + v8::Local cb = ft->GetFunction(); cb->SetName(property); ret_value = cb; } else { - ret_value = PHP_V8JS_CALLBACK(isolate, method_ptr, tmpl); + v8::Local ft; + try { + ft = v8::Local::New + (isolate, ctx->method_tmpls.at(method_ptr)); + } + catch (const std::out_of_range &) { + ft = v8::FunctionTemplate::New(isolate, v8js_php_callback, + v8::External::New((isolate), method_ptr), + v8::Signature::New((isolate), tmpl)); + v8js_tmpl_t *persistent_ft = &ctx->method_tmpls[method_ptr]; + persistent_ft->Reset(isolate, ft); + } + ret_value = ft->GetFunction(); } } } else if (callback_type == V8JS_PROP_QUERY) {