From 9e74bdb97e049511be20322aa85884c1249d3606 Mon Sep 17 00:00:00 2001 From: Vladimir Menshakov Date: Tue, 6 Aug 2013 15:50:43 +0400 Subject: [PATCH 1/8] added virtual dtor to V8ErrorHandler --- Lib/javascript/v8/javascriptruntime.swg | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/javascript/v8/javascriptruntime.swg b/Lib/javascript/v8/javascriptruntime.swg index c2aca8c32..329354d8a 100644 --- a/Lib/javascript/v8/javascriptruntime.swg +++ b/Lib/javascript/v8/javascriptruntime.swg @@ -40,6 +40,7 @@ void SWIG_V8_Raise(const char* msg) { */ class V8ErrorHandler { public: + virtual ~V8ErrorHandler() {} virtual void error(int code, const char* msg) { SWIG_V8_Raise(msg); } From 3af7d543cb52623f962a48f91a129181af29901a Mon Sep 17 00:00:00 2001 From: Vladimir Menshakov Date: Wed, 7 Aug 2013 16:11:59 +0400 Subject: [PATCH 2/8] fixed crash while instantiating generic-wrapped objects from external code, please review --- Lib/javascript/v8/javascriptruntime.swg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/javascript/v8/javascriptruntime.swg b/Lib/javascript/v8/javascriptruntime.swg index 329354d8a..17c33ca09 100644 --- a/Lib/javascript/v8/javascriptruntime.swg +++ b/Lib/javascript/v8/javascriptruntime.swg @@ -171,14 +171,14 @@ void SWIGV8_SetPrivateData(v8::Handle obj, void* ptr, swig_type_info #ifdef BUILDING_NODE_EXTENSION // clientdata must be set for owned data as we need to register the dtor - if(cdata->swigCMemOwn) { + if(cdata->swigCMemOwn && (SWIGV8_ClientData*)info->clientdata) { cdata->handle.MakeWeak(cdata, ((SWIGV8_ClientData*)info->clientdata)->dtor); } else { cdata->handle.MakeWeak(cdata, SWIGV8_Proxy_DefaultDtor); } cdata->handle.MarkIndependent(); #else - if(cdata->swigCMemOwn) { + if(cdata->swigCMemOwn && (SWIGV8_ClientData*)info->clientdata) { cdata->handle.MakeWeak(v8::Isolate::GetCurrent(), cdata, ((SWIGV8_ClientData*)info->clientdata)->dtor); } else { cdata->handle.MakeWeak(v8::Isolate::GetCurrent(), cdata, SWIGV8_Proxy_DefaultDtor); From d5df0bb72101d057b6d59cf7d683263e65288884 Mon Sep 17 00:00:00 2001 From: Eric Wing Date: Wed, 7 Aug 2013 15:11:49 -0700 Subject: [PATCH 3/8] Added #if defined guard for V8_3_14 to allow users from the original SWIG v8 implementation to continue using the new changes. It works similarly to the BUILDING_NODE_EXTENSION in all but two places. This define must be explicitly set by users because there is no way to auto detect. (Perhaps a command line switch can be added to generate this on request?) --- Lib/javascript/v8/javascriptcode.swg | 16 ++++++++-------- Lib/javascript/v8/javascriptruntime.swg | 18 +++++++++--------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index 195141214..42be1a2dc 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -112,14 +112,14 @@ fail: %fragment ("js_dtor", "templates") %{ -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) void $jswrapper(v8::Persistent< v8::Value > object, void *parameter) #else void $jswrapper(v8::Isolate *isolate, v8::Persistent< v8::Object > * object, SWIGV8_Proxy *proxy) #endif { -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) SWIGV8_Proxy *proxy = static_cast(parameter); #endif @@ -132,7 +132,7 @@ void $jswrapper(v8::Isolate *isolate, v8::Persistent< v8::Object > * object, SWI delete proxy; -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) object.Clear(); object.Dispose(); #else @@ -281,7 +281,7 @@ fail: %fragment("jsv8_define_class_template", "templates") %{ v8::Handle $jsmangledname_class = SWIGV8_CreateClassTemplate("$jsmangledname"); -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) $jsmangledname_clientData.class_templ = v8::Persistent::New($jsmangledname_class); #else $jsmangledname_clientData.class_templ.Reset(v8::Isolate::GetCurrent(), $jsmangledname_class); @@ -300,7 +300,7 @@ fail: %{ if (SWIGTYPE_p$jsbaseclass->clientdata && !(static_cast(SWIGTYPE_p$jsbaseclass->clientdata)->class_templ.IsEmpty())) { -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) $jsmangledname_class->Inherit(static_cast(SWIGTYPE_p$jsbaseclass->clientdata)->class_templ); #else $jsmangledname_class->Inherit( @@ -431,7 +431,7 @@ fail: %{ extern "C" { -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) void $jsname_initialize(v8::Handle global_obj, v8::Handle /*module*/) #else void $jsname_initialize(v8::Handle global_obj) @@ -443,7 +443,7 @@ void $jsname_initialize(v8::Handle global_obj) // a class template for creating proxies of undefined types -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) SWIGV8_SWIGTYPE_Proxy_class_templ = v8::Persistent::New(SWIGV8_CreateClassTemplate("SwigProxy")); #else SWIGV8_SWIGTYPE_Proxy_class_templ.Reset(v8::Isolate::GetCurrent(), SWIGV8_CreateClassTemplate("SwigProxy")); @@ -475,7 +475,7 @@ void $jsname_initialize(v8::Handle global_obj) $jsv8registernspaces } -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) NODE_MODULE($jsname, $jsname_initialize); #endif diff --git a/Lib/javascript/v8/javascriptruntime.swg b/Lib/javascript/v8/javascriptruntime.swg index 17c33ca09..fddfcf70c 100644 --- a/Lib/javascript/v8/javascriptruntime.swg +++ b/Lib/javascript/v8/javascriptruntime.swg @@ -74,7 +74,7 @@ public: }; ~SWIGV8_Proxy() { -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) handle.ClearWeak(); #else handle.ClearWeak(v8::Isolate::GetCurrent()); @@ -82,7 +82,7 @@ public: //handle->SetInternalField(0, v8::Undefined()); -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) handle.Dispose(); #else handle.Dispose(v8::Isolate::GetCurrent()); @@ -101,7 +101,7 @@ class SWIGV8_ClientData { public: v8::Persistent class_templ; -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) void (*dtor) (v8::Persistent< v8::Value> object, void *parameter); #else void (*dtor) (v8::Isolate *isolate, v8::Persistent< v8::Object > *object, SWIGV8_Proxy *proxy); @@ -115,7 +115,7 @@ int SWIG_V8_ConvertInstancePtr(v8::Handle objRef, void** ptr, swig_t if(objRef->InternalFieldCount() < 1) return SWIG_ERROR; -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) v8::Handle cdataRef = objRef->GetInternalField(0); SWIGV8_Proxy *cdata = static_cast(v8::External::Unwrap(cdataRef)); #else @@ -142,13 +142,13 @@ int SWIG_V8_ConvertInstancePtr(v8::Handle objRef, void** ptr, swig_t return SWIG_OK; } -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) void SWIGV8_Proxy_DefaultDtor(v8::Persistent< v8::Value > object, void *parameter) #else void SWIGV8_Proxy_DefaultDtor(v8::Isolate *, v8::Persistent< v8::Object > *object, SWIGV8_Proxy *proxy) #endif { -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) SWIGV8_Proxy *proxy = static_cast(parameter); #endif @@ -161,7 +161,7 @@ void SWIGV8_SetPrivateData(v8::Handle obj, void* ptr, swig_type_info cdata->swigCMemOwn = (flags & SWIG_POINTER_OWN) ? 1 : 0; cdata->info = info; -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) obj->SetPointerInInternalField(0, cdata); cdata->handle = v8::Persistent::New(obj); #else @@ -169,7 +169,7 @@ void SWIGV8_SetPrivateData(v8::Handle obj, void* ptr, swig_type_info cdata->handle.Reset(v8::Isolate::GetCurrent(), obj); #endif -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) // clientdata must be set for owned data as we need to register the dtor if(cdata->swigCMemOwn && (SWIGV8_ClientData*)info->clientdata) { cdata->handle.MakeWeak(cdata, ((SWIGV8_ClientData*)info->clientdata)->dtor); @@ -202,7 +202,7 @@ v8::Handle SWIG_V8_NewPointerObj(void *ptr, swig_type_info *info, in v8::Handle class_templ; -#ifdef BUILDING_NODE_EXTENSION +#if defined(BUILDING_NODE_EXTENSION) || defined(V8_3_14) if(info->clientdata != 0) { class_templ = ((SWIGV8_ClientData*) info->clientdata)->class_templ; } else { From ed729f7d3adaf675bbf7f1f800cdcbe17287d987 Mon Sep 17 00:00:00 2001 From: Eric Wing Date: Thu, 11 Jul 2013 19:09:17 -0700 Subject: [PATCH 4/8] This brings over the memory leak fixes for pointers to structs with a %extend destructor from my Neha fork. The generator was not generating and connecting the needed code for the requested destructor to the v8 dtor finalizer. I did not realize this branch has some JavaScriptCore stuff in it too. Unfortunately, it seems to have its own unique problems (like creating C++ files when it should be generating C files). My changes are targeted for v8, and I don't think my JSCore changes fully reach in this JSCore implementation so more work would need to be done to get this branch working. I think my Neha fork is in better shape at the moment. Also, I did port over the 'NULL out the dtor function pointer' in the %nodefaultdtor fix to v8. Usage case: struct MyData { %extend { ~MyData() { FreeData($self); } } }; %newobject CreateData; struct MyData* CreateData(void); %delobject FreeData; void FreeData(struct MyData* the_data); where the use case is something like: var my_data = example.CreateData(); my_data = null; --- Lib/javascript/jsc/javascriptcode.swg | 19 +++++ Lib/javascript/v8/javascriptcode.swg | 21 +++++- Source/Modules/javascript.cxx | 101 +++++++++++++++++++++++++- 3 files changed, 137 insertions(+), 4 deletions(-) diff --git a/Lib/javascript/jsc/javascriptcode.swg b/Lib/javascript/jsc/javascriptcode.swg index 0ad1e364d..40ce9c9b0 100644 --- a/Lib/javascript/jsc/javascriptcode.swg +++ b/Lib/javascript/jsc/javascriptcode.swg @@ -113,6 +113,25 @@ void $jswrapper(JSObjectRef thisObject) } %} +/* ----------------------------------------------------------------------------- + * js_dtor: template for a destructor wrapper + * - $jsmangledname: mangled class name + * - $jstype: class type + * - ${destructor_action}: The custom destructor action to invoke. + * ----------------------------------------------------------------------------- */ +%fragment ("js_dtoroverride", "templates") +%{ +void $jswrapper(JSObjectRef thisObject) +{ + SWIG_PRV_DATA* t = (SWIG_PRV_DATA*) JSObjectGetPrivate(thisObject); + if(t && t->swigCMemOwn) { + $jstype* arg1 = ($jstype*)t->swigCObject; + ${destructor_action} + } + if(t) free(t); +} +%} + /* ----------------------------------------------------------------------------- * js_getter: template for getter function wrappers * - $jswrapper: wrapper function name diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index f86198622..62267ae52 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -114,13 +114,32 @@ fail: 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; +// std::cout << "Deleting wrapped instance: " << proxy->info->name << std::endl; $jsfree proxy->swigCObject; } delete proxy; } %} +/* ----------------------------------------------------------------------------- + * js_dtoroverride: template for a destructor wrapper + * - $jsmangledname: mangled class name + * - $jstype: class type + * - ${destructor_action}: The custom destructor action to invoke. + * ----------------------------------------------------------------------------- */ +%fragment ("js_dtoroverride", "templates") +%{ +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; + $jstype arg1 = ($jstype)t->swigCObject; + ${destructor_action} + } + delete proxy; +} +%} + /* ----------------------------------------------------------------------------- * js_getter: template for getter function wrappers * - $jswrapper: wrapper function name diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index 8850ebd60..a8f1b0b0a 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -886,7 +886,6 @@ int JSEmitter::emitCtor(Node *n) { int JSEmitter::emitDtor(Node *n) { - Template t_dtor = getTemplate("js_dtor"); String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name")); SwigType *type = state.clazz(TYPE); @@ -894,20 +893,116 @@ int JSEmitter::emitDtor(Node *n) { String *ctype = SwigType_lstr(p_classtype, ""); String *free = NewString(""); + // (Taken from JSCore implementation.) + /* The if (Extend) block was taken from the Ruby implementation. + * The problem is that in the case of an %extend to create a destructor for a struct to coordinate automatic memory cleanup with the Javascript collector, + * the swig function was not being generated. More specifically: + struct MyData { + %extend { + ~MyData() { + FreeData($self); + } + } + }; + %newobject CreateData; + struct MyData* CreateData(void); + %delobject FreeData; + void FreeData(struct MyData* the_data); + + where the use case is something like: + var my_data = example.CreateData(); + my_data = null; + + This function was not being generated: + SWIGINTERN void delete_MyData(struct MyData *self){ + FreeData(self); + } + + I don't understand fully why it wasn't being generated. It just seems to happen in the Lua generator. + There is a comment about staticmemberfunctionHandler having an inconsistency and I tracked down dome of the SWIGINTERN void delete_* + code to that function in the Language base class. + The Ruby implementation seems to have an explicit check for if(Extend) and explicitly generates the code, so that's what I'm doing here. + The Ruby implementation does other stuff which I omit. + */ + if (Extend) { + String *wrap = Getattr(n, "wrap:code"); + if (wrap) { + Printv(f_wrappers, wrap, NIL); + } + } + + // HACK: this is only for the v8 emitter. maybe set an attribute wrap:action of node // TODO: generate dtors more similar to other wrappers + // EW: I think this is wrong. delete should only be used when new was used to create. If malloc was used, free needs to be used. if(SwigType_isarray(type)) { Printf(free, "delete [] (%s)", ctype); } else { Printf(free, "delete (%s)", ctype); } - state.clazz(DTOR, wrap_name); - t_dtor.replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED)) + String* destructor_action = Getattr(n, "wrap:action"); + // Adapted from the JSCore implementation. + /* The next challenge is to generate the correct finalize function for JavaScriptCore to call. + Originally, it would use this fragment from javascriptcode.swg + %fragment ("JS_destructordefn", "templates") + %{ + void _wrap_${classname_mangled}_finalize(JSObjectRef thisObject) + { + SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); + if(t && t->swigCMemOwn) free ((${type}*)t->swigCObject); + if(t) free(t); + } + %} + + But for the above example case of %extend to define a destructor on a struct, we need to override the system to not call + free ((${type}*)t->swigCObject); + and substitute it with what the user has provided. + To solve this, I created a variation fragment called JS_destructoroverridedefn: + SWIG_PRV_DATA* t = (SWIG_PRV_DATA*)JSObjectGetPrivate(thisObject); + if(t && t->swigCMemOwn) { + ${type}* arg1 = (${type}*)t->swigCObject; + ${destructor_action} + } + if(t) free(t); + + Based on what I saw in the Lua and Ruby modules, I use Getattr(n, "wrap:action") + to decide if the user has a preferred destructor action. + Based on that, I decide which fragment to use. + And in the case of the custom action, I substitute that action in. + I noticed that destructor_action has the form + delete_MyData(arg1); + The explicit arg1 is a little funny, so I structured the fragment to create a temporary variable called arg1 to make the generation easier. + This might suggest this solution misunderstands a more complex case. + + Also, there is a problem where destructor_action is always true for me, even when not requesting %extend as above. + So this code doesn't actually quite work as I expect. The end result is that the code still works because + destructor_action calls free like the original template. The one caveat is the string in destructor_action casts to char* which is wierd. + I think there is a deeper underlying SWIG issue because I don't think it should be char*. However, it doesn't really matter for free. + + Maybe the fix for the destructor_action always true problem is that this is supposed to be embedded in the if(Extend) block above. + But I don't fully understand the conditions of any of these things, and since it works for the moment, I don't want to break more stuff. + */ + if(destructor_action) { + Template t_dtor = getTemplate("js_dtoroverride"); + state.clazz(DTOR, wrap_name); + t_dtor.replace("${classname_mangled}", state.clazz(NAME_MANGLED)) + .replace(T_WRAPPER, wrap_name) + .replace(T_FREE, free) + .replace(T_TYPE, ctype); + + t_dtor.replace("${destructor_action}", destructor_action); + Wrapper_pretty_print(t_dtor.str(), f_wrappers); + } + else { + Template t_dtor = getTemplate("js_dtor"); + state.clazz(DTOR, wrap_name); + t_dtor.replace(T_NAME_MANGLED, state.clazz(NAME_MANGLED)) .replace(T_WRAPPER, wrap_name) .replace(T_FREE, free) .replace(T_TYPE, ctype) .pretty_print(f_wrappers); + } Delete(p_classtype); Delete(ctype); From f8feeacb68593063914c58c60e408d8515295b7f Mon Sep 17 00:00:00 2001 From: Eric Wing Date: Thu, 11 Jul 2013 19:11:56 -0700 Subject: [PATCH 5/8] v8: Removed the extern "C" around the initialize function because it makes no sense since it requires a C++ templates object as a parameter. --- Lib/javascript/v8/javascriptcode.swg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index 62267ae52..003658613 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -403,7 +403,8 @@ fail: * ----------------------------------------------------------------------------- */ %fragment("js_initializer", "templates") %{ -extern "C" { +// The extern "C" makes little sense here because the paramater is using C++ objects and templates. +// extern "C" { void $jsname_initialize(v8::Handle global_obj) { @@ -440,5 +441,5 @@ void $jsname_initialize(v8::Handle global_obj) } -} // extern "C" +// } // extern "C" %} From 65a0be8876959dd9a79bc3d7290af15ab646202d Mon Sep 17 00:00:00 2001 From: Eric Wing Date: Thu, 11 Jul 2013 20:04:01 -0700 Subject: [PATCH 6/8] v8: variable name bug fix in my template modifications for pointers to structs. --- Lib/javascript/v8/javascriptcode.swg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/javascript/v8/javascriptcode.swg b/Lib/javascript/v8/javascriptcode.swg index 003658613..ef3d1f896 100644 --- a/Lib/javascript/v8/javascriptcode.swg +++ b/Lib/javascript/v8/javascriptcode.swg @@ -133,7 +133,7 @@ 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; - $jstype arg1 = ($jstype)t->swigCObject; + $jstype arg1 = ($jstype)proxy->swigCObject; ${destructor_action} } delete proxy; From 4503c5390304202275a849eaa8473985adf86f02 Mon Sep 17 00:00:00 2001 From: Eric Wing Date: Wed, 7 Aug 2013 15:12:36 -0700 Subject: [PATCH 7/8] Since this code uses assert, #include is needed. --- Lib/javascript/v8/javascriptinit.swg | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/javascript/v8/javascriptinit.swg b/Lib/javascript/v8/javascriptinit.swg index 684728023..13ec1aff8 100644 --- a/Lib/javascript/v8/javascriptinit.swg +++ b/Lib/javascript/v8/javascriptinit.swg @@ -1,5 +1,6 @@ %insert(init) %{ +#include SWIGRUNTIME void SWIG_V8_SetModule(void *, swig_module_info *swig_module) { From 0732592ed99759afab2f05e6be1723659e955464 Mon Sep 17 00:00:00 2001 From: Kota Iguchi Date: Wed, 7 Aug 2013 18:10:53 -0700 Subject: [PATCH 8/8] Patch to support argout typemap for your swig-v8 branch. --- Source/Modules/javascript.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Source/Modules/javascript.cxx b/Source/Modules/javascript.cxx index 8c82890a6..6eb2c572d 100644 --- a/Source/Modules/javascript.cxx +++ b/Source/Modules/javascript.cxx @@ -1285,6 +1285,16 @@ void JSEmitter::emitCleanupCode(Node *n, Wrapper *wrapper, ParmList *params) { Parm *p; String *tm; + for (p = params; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(wrapper->code, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + for (p = params; p;) { if ((tm = Getattr(p, "tmap:freearg"))) { //addThrows(n, "tmap:freearg", p);