aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/embind/emval.js35
-rw-r--r--system/include/emscripten/val.h65
-rw-r--r--system/include/emscripten/wire.h31
-rw-r--r--tests/embind/embind.test.js15
4 files changed, 77 insertions, 69 deletions
diff --git a/src/embind/emval.js b/src/embind/emval.js
index d4e4271d..039f1d61 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -79,6 +79,12 @@ function __emval_decref(handle) {
}
}
+function __emval_run_destructors(handle) {
+ var destructors = _emval_handle_array[handle].value;
+ runDestructors(destructors);
+ __emval_decref(handle);
+}
+
function __emval_new_array() {
return __emval_register([]);
}
@@ -199,12 +205,12 @@ function __emval_set_property(handle, key, value) {
_emval_handle_array[handle].value[_emval_handle_array[key].value] = _emval_handle_array[value].value;
}
-function __emval_as(handle, returnType, runDestructorsRef) {
+function __emval_as(handle, returnType, destructorsRef) {
requireHandle(handle);
returnType = requireRegisteredType(returnType, 'emval::as');
var destructors = [];
- var rd = __emval_register(runDestructors.bind(undefined, destructors));
- HEAP32[runDestructorsRef >> 2] = rd;
+ var rd = __emval_register(destructors);
+ HEAP32[destructorsRef >> 2] = rd;
return returnType['toWireType'](destructors, _emval_handle_array[handle].value);
}
@@ -243,14 +249,20 @@ function lookupTypes(argCount, argTypes, argWireTypes) {
return a;
}
+function allocateDestructors(destructorsRef) {
+ var destructors = [];
+ HEAP32[destructorsRef >> 2] = __emval_register(destructors);
+ return destructors;
+}
+
function __emval_get_method_caller(argCount, argTypes) {
var types = lookupTypes(argCount, argTypes);
var retType = types[0];
var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$";
- var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"];
- var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType];
+ var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType", "allocateDestructors"];
+ var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType, allocateDestructors];
var argsList = ""; // 'arg0, arg1, arg2, ... , argN'
var argsListWired = ""; // 'arg0Wired, ..., argNWired'
@@ -262,16 +274,17 @@ function __emval_get_method_caller(argCount, argTypes) {
}
var invokerFnBody =
- "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" +
- "requireHandle(handle);\n" +
- "name = getStringOrSymbol(name);\n";
+ "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name, destructorsRef" + argsListWired + ") {\n" +
+ " requireHandle(handle);\n" +
+ " name = getStringOrSymbol(name);\n";
for (var i = 0; i < argCount - 1; ++i) {
- invokerFnBody += "var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n";
+ invokerFnBody += " var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n";
}
invokerFnBody +=
- "var obj = _emval_handle_array[handle].value;\n" +
- "return retType.toWireType(null, obj[name](" + argsList + "));\n" +
+ " var obj = _emval_handle_array[handle].value;\n" +
+ " var rv = obj[name](" + argsList + ");\n" +
+ " return retType.toWireType(allocateDestructors(destructorsRef), rv);\n" +
"}));\n";
args1.push(invokerFnBody);
diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h
index 5a04d30f..19b1beb1 100644
--- a/system/include/emscripten/val.h
+++ b/system/include/emscripten/val.h
@@ -11,6 +11,7 @@ namespace emscripten {
void _emval_register_symbol(const char*);
typedef struct _EM_VAL* EM_VAL;
+ typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS;
// TODO: functions returning this are reinterpret_cast
// into the correct return type. this needs some thought
@@ -20,6 +21,8 @@ namespace emscripten {
void _emval_incref(EM_VAL value);
void _emval_decref(EM_VAL value);
+ void _emval_run_destructors(EM_DESTRUCTORS handle);
+
EM_VAL _emval_new_array();
EM_VAL _emval_new_object();
EM_VAL _emval_undefined();
@@ -37,7 +40,7 @@ namespace emscripten {
EM_VAL _emval_get_module_property(const char* name);
EM_VAL _emval_get_property(EM_VAL object, EM_VAL key);
void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value);
- _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_VAL* runDestructors);
+ _POLYMORPHIC_RESULT _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* runDestructors);
EM_VAL _emval_call(
EM_VAL value,
@@ -63,7 +66,11 @@ namespace emscripten {
template<typename ReturnType, typename... Args>
struct Signature {
- typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(EM_VAL value, const char* methodName, typename BindingType<Args>::WireType...);
+ typedef typename BindingType<ReturnType>::WireType (*MethodCaller)(
+ EM_VAL value,
+ const char* methodName,
+ EM_DESTRUCTORS* destructors,
+ typename BindingType<Args>::WireType...);
static MethodCaller get_method_caller() {
static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller());
@@ -77,15 +84,34 @@ namespace emscripten {
}
};
+ struct DestructorsRunner {
+ public:
+ explicit DestructorsRunner(EM_DESTRUCTORS d)
+ : destructors(d)
+ {}
+ ~DestructorsRunner() {
+ _emval_run_destructors(destructors);
+ }
+
+ DestructorsRunner(const DestructorsRunner&) = delete;
+ void operator=(const DestructorsRunner&) = delete;
+
+ private:
+ EM_DESTRUCTORS destructors;
+ };
+
template<typename ReturnType, typename... Args>
struct MethodCaller {
static ReturnType call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<ReturnType, Args...>::get_method_caller();
+
+ EM_DESTRUCTORS destructors;
auto wireType = caller(
handle,
methodName,
+ &destructors,
toWireType(std::forward<Args>(args))...);
- WireDeleter<ReturnType> deleter(wireType);
+ DestructorsRunner rd(destructors);
return BindingType<ReturnType>::fromWireType(wireType);
}
};
@@ -94,28 +120,17 @@ namespace emscripten {
struct MethodCaller<void, Args...> {
static void call(EM_VAL handle, const char* methodName, Args&&... args) {
auto caller = Signature<void, Args...>::get_method_caller();
- return caller(
+
+ EM_DESTRUCTORS destructors;
+ caller(
handle,
methodName,
+ &destructors,
toWireType(std::forward<Args>(args))...);
+ DestructorsRunner rd(destructors);
+ // void requires no translation
}
};
-
- struct DestructorsRunner {
- public:
- DestructorsRunner(EM_VAL v)
- : dr(v)
- {}
- DestructorsRunner(const DestructorsRunner&) = delete;
- void operator=(const DestructorsRunner&) = delete;
- ~DestructorsRunner() {
- EM_VAL rv = _emval_call(dr, 0, 0);
- _emval_decref(rv); // TODO: if we had an _emval_call_void we wouldn't need this
- _emval_decref(dr);
- }
- private:
- EM_VAL dr;
- };
}
#define EMSCRIPTEN_SYMBOL(name) \
@@ -285,12 +300,12 @@ namespace emscripten {
typedef typename BT::WireType (*TypedAs)(
EM_VAL value,
TYPEID returnType,
- EM_VAL* runDestructors);
+ EM_DESTRUCTORS* runDestructors);
TypedAs typedAs = reinterpret_cast<TypedAs>(&_emval_as);
- EM_VAL runDestructors;
- typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &runDestructors);
- DestructorsRunner dr(runDestructors);
+ EM_DESTRUCTORS destructors;
+ typename BT::WireType wt = typedAs(handle, TypeID<T>::get(), &destructors);
+ DestructorsRunner dr(destructors);
return BT::fromWireType(wt);
}
@@ -316,8 +331,6 @@ namespace emscripten {
static val fromWireType(WireType v) {
return val::take_ownership(v);
}
- static void destroy(WireType v) {
- }
};
}
diff --git a/system/include/emscripten/wire.h b/system/include/emscripten/wire.h
index 70deb2c7..c3ce8dd0 100644
--- a/system/include/emscripten/wire.h
+++ b/system/include/emscripten/wire.h
@@ -131,8 +131,6 @@ namespace emscripten {
constexpr static type fromWireType(WireType v) { \
return v; \
} \
- static void destroy(WireType) { \
- } \
}
EMSCRIPTEN_DEFINE_NATIVE_BINDING_TYPE(char);
@@ -161,8 +159,6 @@ namespace emscripten {
static bool fromWireType(WireType wt) {
return wt;
}
- static void destroy(WireType) {
- }
};
template<>
@@ -180,9 +176,6 @@ namespace emscripten {
static std::string fromWireType(WireType v) {
return std::string(v->data, v->length);
}
- static void destroy(WireType v) {
- free(v);
- }
};
template<>
@@ -200,9 +193,6 @@ namespace emscripten {
static std::wstring fromWireType(WireType v) {
return std::wstring(v->data, v->length);
}
- static void destroy(WireType v) {
- free(v);
- }
};
template<typename T>
@@ -255,10 +245,6 @@ namespace emscripten {
static ActualT& fromWireType(WireType p) {
return *p;
}
-
- static void destroy(WireType p) {
- delete p;
- }
};
// Is this necessary?
@@ -281,8 +267,6 @@ namespace emscripten {
static Enum fromWireType(WireType v) {
return v;
}
- static void destroy(WireType) {
- }
};
// catch-all generic binding
@@ -297,21 +281,6 @@ namespace emscripten {
auto toWireType(T&& v) -> typename BindingType<T>::WireType {
return BindingType<T>::toWireType(std::forward<T>(v));
}
-
- template<typename T>
- struct WireDeleter {
- typedef typename BindingType<T>::WireType WireType;
-
- WireDeleter(WireType wt)
- : wt(wt)
- {}
-
- ~WireDeleter() {
- BindingType<T>::destroy(wt);
- }
-
- WireType wt;
- };
}
struct memory_view {
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index a36c8b08..5ca972be 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1591,7 +1591,7 @@ module({
test("returning a new shared pointer from interfaces implemented in JS code does not leak", function() {
var impl = cm.AbstractClass.implement({
returnsSharedPtr: function() {
- return cm.embind_test_return_smart_derived_ptr();
+ return cm.embind_test_return_smart_derived_ptr().deleteLater();
}
});
cm.callReturnsSharedPtrMethod(impl);
@@ -1925,6 +1925,19 @@ module({
a.delete();
});
});
+
+ test("returning a cached new shared pointer from interfaces implemented in JS code does not leak", function() {
+ var derived = cm.embind_test_return_smart_derived_ptr();
+ var impl = cm.AbstractClass.implement({
+ returnsSharedPtr: function() {
+ return derived;
+ }
+ });
+ cm.callReturnsSharedPtrMethod(impl);
+ impl.delete();
+ derived.delete();
+ // Let the memory leak test superfixture check that no leaks occurred.
+ });
});
/* global run_all_tests */