From f814a8e702dcfe2ae2f2480de372e78c5a997eb5 Mon Sep 17 00:00:00 2001 From: Oliver Buchtala Date: Sat, 8 Sep 2012 01:14:02 +0000 Subject: [PATCH] Fix errors concerning object wrapping and cleanup in v8 emitter. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/branches/oliverb-javascript-v8@13819 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Lib/javascript/v8/javascriptcode.swg | 30 ++++++++--- Lib/javascript/v8/javascripthelpers.swg | 4 +- Lib/javascript/v8/javascriptinit.swg | 2 + Lib/javascript/v8/javascriptruntime.swg | 71 +++++++++++++------------ Source/Modules/javascript.cxx | 64 +++++++++++++++++++--- 5 files changed, 122 insertions(+), 49 deletions(-) diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index b7b2c195f..8f3d8cff2 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -5,7 +5,7 @@ v8::Handle $jswrapper(const v8::Arguments& args) { $jslocals $jscode - SWIG_V8_SetPrivateData(self, result, SWIGTYPE_$jsmangledtype, SWIG_POINTER_OWN); + SWIGV8_SetPrivateData(self, result, SWIGTYPE_$jsmangledtype, SWIG_POINTER_OWN); return scope.Close(self); goto fail; @@ -48,7 +48,14 @@ fail: %fragment ("JS_destructordefn", "templates") %{ - // TODO: implement JS_destructordefn +void $jswrapper(v8::Persistent< v8::Value > object, void *parameter) { + SWIGV8_Proxy* proxy = (SWIGV8_Proxy*) parameter; + if(proxy->swigCMemOwn && proxy->swigCObject) { + std::cout << "Deleting wrapped instance: " << proxy->info->name << std::endl; + delete ($jstype*) proxy->swigCObject; + } + delete proxy; +} %} @@ -136,18 +143,25 @@ fail: %} %fragment("jsv8_declare_class_template", "templates") -%{v8::Persistent $jsmangledname_class;%} +%{SWIGV8_ClientData $jsmangledname_clientData; +%} %fragment("jsv8_define_class_template", "templates") -%{$jsmangledname_class = SWIGV8_CreateClassTemplate("$jsname" , $jsctor); - SWIGTYPE_$jsmangledtype->clientdata = &$jsmangledname_class;%} - -%fragment("jsv8_create_class_instance", "templates") -%{v8::Handle $jsmangledname_obj = $jsmangledname_class->GetFunction();%} +%{v8::Handle $jsmangledname_class = SWIGV8_CreateClassTemplate("$jsmangledname"); + $jsmangledname_clientData.class_templ = $jsmangledname_class; + $jsmangledname_clientData.dtor = $jsdtor; + SWIGTYPE_p$jsmangledtype->clientdata = &$jsmangledname_clientData;%} %fragment("jsv8_inherit", "templates") %{$jsmangledname_class->Inherit($jsbaseclass_class);%} +%fragment("jsv8_create_class_instance", "templates") +%{v8::Handle $jsmangledname_class_0 = SWIGV8_CreateClassTemplate("$jsname"); + $jsmangledname_class_0->SetCallHandler($jsctor); + $jsmangledname_class_0->Inherit($jsmangledname_class); + $jsmangledname_class_0->SetHiddenPrototype(true); + v8::Handle $jsmangledname_obj = $jsmangledname_class_0->GetFunction();%} + %fragment("jsv8_register_class", "templates") %{$jsparent_obj->Set(v8::String::NewSymbol("$jsname"), $jsmangledname_obj);%} diff --git a/Lib/javascript/v8/javascripthelpers.swg b/Lib/javascript/v8/javascripthelpers.swg index 9a80a6552..4fcf0e447 100644 --- a/Lib/javascript/v8/javascripthelpers.swg +++ b/Lib/javascript/v8/javascripthelpers.swg @@ -3,8 +3,8 @@ /** * Creates a class template for a class with specified initialization function. */ -v8::Persistent SWIGV8_CreateClassTemplate(const char* symbol, v8::InvocationCallback _func) { - v8::Local class_templ = v8::FunctionTemplate::New(_func); +v8::Persistent SWIGV8_CreateClassTemplate(const char* symbol) { + v8::Local class_templ = v8::FunctionTemplate::New(); class_templ->SetClassName(v8::String::NewSymbol(symbol)); v8::Handle inst_templ = class_templ->InstanceTemplate(); diff --git a/Lib/javascript/v8/javascriptinit.swg b/Lib/javascript/v8/javascriptinit.swg index 1186b33bc..1bca4c244 100644 --- a/Lib/javascript/v8/javascriptinit.swg +++ b/Lib/javascript/v8/javascriptinit.swg @@ -12,4 +12,6 @@ SWIG_V8_GetModule(void) { %} +%insert(init) %{/************ BEGIN: "swiginit.swg" *******************/ %} %insert(init) "swiginit.swg" +%insert(init) %{/************ END: "swiginit.swg" *******************/ %} diff --git a/Lib/javascript/v8/javascriptruntime.swg b/Lib/javascript/v8/javascriptruntime.swg index 2eb9c82cc..b9f24a562 100644 --- a/Lib/javascript/v8/javascriptruntime.swg +++ b/Lib/javascript/v8/javascriptruntime.swg @@ -8,6 +8,7 @@ #include #include #include +#include %} %insert(runtime) "swigrun.swg"; /* SWIG API */ @@ -59,27 +60,45 @@ public: %} %insert(runtime) %{ -typedef struct { + +// Note: to trigger the c8 gc more often one can tell v8 about the memory consumption +// TODO: we could add a v8 specific parameter to control this value +#define SWIGV8_AVG_OBJ_SIZE 1000 + +class SWIGV8_Proxy { +public: + SWIGV8_Proxy(): swigCMemOwn(false), swigCObject(0), info(0) { + v8::V8::AdjustAmountOfExternalAllocatedMemory(SWIGV8_AVG_OBJ_SIZE); + }; + + ~SWIGV8_Proxy() { + v8::V8::AdjustAmountOfExternalAllocatedMemory(-SWIGV8_AVG_OBJ_SIZE); + } + bool swigCMemOwn; void *swigCObject; swig_type_info *info; -} SWIG_PRV_DATA; +}; + +class SWIGV8_ClientData { +public: + v8::Handle class_templ; + void (*dtor) (v8::Persistent< v8::Value > object, void *parameter); +}; + %} %insert(runtime) %{ int SWIG_V8_ConvertInstancePtr(v8::Handle objRef, void** ptr, swig_type_info *info, int flags) { + v8::HandleScope scope; - if(objRef->InternalFieldCount() < 1) { - return SWIG_ERROR; - } + if(objRef->InternalFieldCount() < 1) return SWIG_ERROR; v8::Handle cdataRef = objRef->GetInternalField(0); - - SWIG_PRV_DATA *cdata = (SWIG_PRV_DATA *) v8::External::Unwrap(cdataRef); + SWIGV8_Proxy *cdata = (SWIGV8_Proxy *) v8::External::Unwrap(cdataRef); if(cdata == NULL) { return SWIG_ERROR; } - if(cdata->info != info) { bool type_valid = false; swig_cast_info *t = info->cast; @@ -94,53 +113,39 @@ int SWIG_V8_ConvertInstancePtr(v8::Handle objRef, void** ptr, swig_t return SWIG_TypeError; } } - *ptr = cdata->swigCObject; - if(flags & SWIG_POINTER_DISOWN) { cdata->swigCMemOwn = false; } - return SWIG_OK; } -void SWIG_V8_SetPrivateData(v8::Handle obj, void* ptr, swig_type_info *info, int flags) { - SWIG_PRV_DATA* cdata = (SWIG_PRV_DATA*) new SWIG_PRV_DATA; +void SWIGV8_SetPrivateData(v8::Handle obj, void* ptr, swig_type_info *info, int flags) { + SWIGV8_Proxy* cdata = new SWIGV8_Proxy(); cdata->swigCObject = ptr; cdata->swigCMemOwn = (flags & SWIG_POINTER_OWN) ? 1 : 0; cdata->info = info; - - obj->SetInternalField(0, v8::External::New(cdata)); + obj->SetPointerInInternalField(0, cdata); + v8::Persistent weakptr = v8::Persistent::New(obj); + weakptr.MakeWeak(cdata, ((SWIGV8_ClientData*)info->clientdata)->dtor); } int SWIG_V8_ConvertPtr(v8::Handle valRef, void** ptr, swig_type_info *info, int flags) { + v8::HandleScope scope; + if(!valRef->IsObject()) { return SWIG_TypeError; } - v8::Handle objRef = valRef->ToObject(); - return SWIG_V8_ConvertInstancePtr(objRef, ptr, info, flags); } v8::Handle SWIG_V8_NewPointerObj(void *ptr, swig_type_info *info, int flags) { v8::HandleScope scope; - - v8::Local class_templ; - v8::Handle inst_templ; - if(info->clientdata == NULL) { - class_templ = v8::FunctionTemplate::New(); - class_templ->SetClassName(v8::String::NewSymbol(info->name)); - inst_templ = class_templ->InstanceTemplate(); - inst_templ->SetInternalFieldCount(1); - } else { - class_templ = *((v8::Local*) info->clientdata); - inst_templ = class_templ->InstanceTemplate(); - } - - v8::Local result = inst_templ->NewInstance(); - - SWIG_V8_SetPrivateData(result, ptr, info, flags); + + v8::Handle class_templ = ((SWIGV8_ClientData*) info->clientdata)->class_templ; + v8::Handle result = class_templ->InstanceTemplate()->NewInstance(); + SWIGV8_SetPrivateData(result, ptr, info, flags); return scope.Close(result); } diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index 28c4b96b7..f54d470f1 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -20,6 +20,7 @@ bool js_template_enable_debug = false; #define CTOR "ctor" #define CTOR_WRAPPERS "ctor_wrappers" #define CTOR_DISPATCHERS "ctor_dispatchers" +#define DTOR "dtor" #define ARGCOUNT "wrap:argc" #define FUNCTION_DISPATCHERS "function_dispatchers" @@ -31,6 +32,7 @@ bool js_template_enable_debug = false; #define T_TYPE_MANGLED "$jsmangledtype" #define T_WRAPPER "$jswrapper" #define T_CTOR "$jsctor" +#define T_DTOR "$jsdtor" #define T_GETTER "$jsgetter" #define T_SETTER "$jssetter" #define T_DISPATCH_CASES "$jsdispatchcases" @@ -292,6 +294,8 @@ protected: Hash *namespaces; Hash *current_namespace; + Hash *undefined_types; + String *defaultResultName; File *f_wrappers; @@ -597,6 +601,7 @@ JSEmitter::JSEmitter() : templates(NewHash()), namespaces(NULL), current_namespace(NULL), + undefined_types(NewHash()), defaultResultName(NewString("result")), f_wrappers(NULL) { @@ -751,6 +756,7 @@ int JSEmitter::enterClass(Node *n) { Append(ctor_wrapper, state.clazz(NAME)); state.clazz(CTOR, ctor_wrapper); state.clazz(CTOR_DISPATCHERS, NewString("")); + state.clazz(DTOR, NewString("0")); // HACK: assume that a class is abstract // this is resolved by emitCtor (which is only called for non abstract classes) @@ -855,10 +861,13 @@ int JSEmitter::emitCtor(Node *n) { return SWIG_OK; } -int JSEmitter::emitDtor(Node *) { +int JSEmitter::emitDtor(Node *n) { Template t_dtor = getTemplate("JS_destructordefn"); + String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); + state.clazz(DTOR, wrap_name); t_dtor.replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED)) + .replace(T_WRAPPER, wrap_name) .replace(T_TYPE, state.clazz(TYPE)) .pretty_print(f_wrappers); @@ -1068,8 +1077,11 @@ void JSEmitter::marshalOutput(Node *n, Wrapper *wrapper, String *actioncode, co Setattr(n, "type", type); String *tm; - // HACK: output types are not registered as swig_types automatically - if (SwigType_ispointer(type)) SwigType_remember_clientdata(type, NewString("0")); + // register undefined wrappers + if (SwigType_ispointer(type) && !Language::instance()->classLookup(type)) { + SwigType_remember_clientdata(type, 0); + Setattr(undefined_types, SwigType_manglestr(type), type); + } // adds a declaration for the result variable if(emitReturnVariable) emit_return_variable(n, type, wrapper); @@ -1565,6 +1577,7 @@ protected: virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper, MarshallingMode mode, bool is_member, bool is_static); virtual int emitNamespaces(); + virtual void emitUndefined(); private: @@ -1654,6 +1667,8 @@ int V8Emitter::dump(Node *n) SwigType_emit_type_table(f_runtime, f_wrappers); + emitUndefined(); + Printv(f_wrap_cpp, f_runtime, "\n", 0); Printv(f_wrap_cpp, f_header, "\n", 0); Printv(f_wrap_cpp, f_class_templates, "\n", 0); @@ -1724,19 +1739,22 @@ int V8Emitter::exitClass(Node *n) } /* Note: this makes sure that there is a swig_type added for this class */ - SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0")); + String *clientData = NewString(""); + Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED)); + SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), clientData); // emit definition of v8 class template Template t_def_class(getTemplate("jsv8_define_class_template")); t_def_class.replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED)) .replace(T_NAME, state.clazz(NAME)) - .replace(T_CTOR, state.clazz(CTOR)) - .replace(T_TYPE_MANGLED, state.clazz(TYPE_MANGLED)) + .replace(T_TYPE_MANGLED, SwigType_manglestr(Getattr(n, "classtype"))) + .replace(T_DTOR, state.clazz(DTOR)) .pretty_print(f_init_class_templates); Template t_class_instance(getTemplate("jsv8_create_class_instance")); t_class_instance.replace(T_NAME, state.clazz(NAME)) .replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED)) + .replace(T_CTOR, state.clazz(CTOR)) .pretty_print(f_init_class_instances); // emit inheritance setup @@ -1929,6 +1947,40 @@ int V8Emitter::emitNamespaces() { return SWIG_OK; } +void V8Emitter::emitUndefined() { + Iterator ki; + for (ki = First(undefined_types); ki.item; ki = Next(ki)) { + String *mangled_name = ki.key; + String *dtor = Swig_name_destroy("", mangled_name); + SwigType *deref = SwigType_del_pointer(ki.item); + String *type_mangled = SwigType_manglestr(ki.item); + + // emit clientData declaration + Template clientDataDecl = getTemplate("jsv8_declare_class_template"); + clientDataDecl.replace(T_NAME_MANGLED, mangled_name) + .pretty_print(f_class_templates); + + // emit an extra dtor for unknown types + Template t_dtor = getTemplate("JS_destructordefn"); + t_dtor.replace(T_NAME_MANGLED, mangled_name) + .replace(T_WRAPPER, dtor) + .replace(T_TYPE, deref) + .pretty_print(f_wrappers); + + // create a class template and initialize clientData + Template clientDataDef = getTemplate("jsv8_define_class_template"); + clientDataDef.replace(T_NAME_MANGLED, mangled_name) + .replace(T_NAME, mangled_name) + .replace(T_TYPE_MANGLED, type_mangled) + .replace(T_DTOR, dtor) + .pretty_print(f_init_class_templates); + + Delete(dtor); + Delete(deref); + Delete(type_mangled); + + } +} JSEmitter *swig_javascript_create_V8Emitter() { return new V8Emitter();