aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/embind/embind.js9
-rw-r--r--src/embind/emval.js9
-rw-r--r--tests/embind/embind.test.js47
-rw-r--r--tests/embind/embind_test.cpp31
4 files changed, 95 insertions, 1 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 9f3e6eff..124ea569 100644
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -590,6 +590,9 @@ function __embind_register_emval(rawType, name) {
'argPackAdvance': 8,
'readValueFromPointer': simpleReadValueFromPointer,
destructorFunction: null, // This type does not need a destructor
+
+ // TODO: do we need a deleteObject here? write a test where
+ // emval is passed into JS via an interface
});
}
@@ -1195,6 +1198,12 @@ RegisteredPointer.prototype.destructor = function destructor(ptr) {
RegisteredPointer.prototype['argPackAdvance'] = 8;
RegisteredPointer.prototype['readValueFromPointer'] = simpleReadValueFromPointer;
+RegisteredPointer.prototype['deleteObject'] = function deleteObject(handle) {
+ if (handle !== null) {
+ handle['delete']();
+ }
+};
+
RegisteredPointer.prototype['fromWireType'] = function fromWireType(ptr) {
// ptr is a raw pointer (or a raw smartpointer)
diff --git a/src/embind/emval.js b/src/embind/emval.js
index 2b49fc83..1661bc02 100644
--- a/src/embind/emval.js
+++ b/src/embind/emval.js
@@ -265,7 +265,14 @@ function __emval_get_method_caller(argCount, argTypes) {
" args += argType" + i + ".argPackAdvance;\n";
}
functionBody +=
- " var rv = handle[name](" + argsList + ");\n" +
+ " var rv = handle[name](" + argsList + ");\n";
+ for (var i = 0; i < argCount - 1; ++i) {
+ if (types[i + 1]['deleteObject']) {
+ functionBody +=
+ " argType" + i + ".deleteObject(arg" + i + ");\n";
+ }
+ }
+ functionBody +=
" return retType.toWireType(destructors, rv);\n" +
"};\n";
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index ae421f27..a6b2e98c 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -1953,6 +1953,53 @@ module({
rv.delete();
cm.flushPendingDeletes();
});
+
+ test("method arguments with pointer ownership semantics are cleaned up after call", function() {
+ var parent = cm.AbstractClass;
+ var C = parent.extend("C", {
+ abstractMethod: function() {
+ },
+ });
+ var impl = new C;
+ cm.passShared(impl);
+ impl.delete();
+ });
+
+ test("method arguments with pointer ownership semantics can be cloned", function() {
+ var parent = cm.AbstractClass;
+ var owned;
+ var C = parent.extend("C", {
+ abstractMethod: function() {
+ },
+ passShared: function(p) {
+ owned = p.clone();
+ }
+ });
+ var impl = new C;
+ cm.passShared(impl);
+ impl.delete();
+
+ assert.equal("Derived", owned.getClassName());
+ owned.delete();
+ });
+
+ test("emscripten::val method arguments don't leak", function() {
+ var parent = cm.AbstractClass;
+ var got;
+ var C = parent.extend("C", {
+ abstractMethod: function() {
+ },
+ passVal: function(g) {
+ got = g;
+ }
+ });
+ var impl = new C;
+ var v = {};
+ cm.passVal(impl, v);
+ impl.delete();
+
+ assert.equal(v, got);
+ });
});
BaseFixture.extend("registration order", function() {
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index eb534134..a0cb858d 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -1094,6 +1094,12 @@ public:
std::string concreteMethod() const {
return "concrete";
}
+
+ virtual void passShared(const std::shared_ptr<Derived>&) {
+ }
+
+ virtual void passVal(const val& v) {
+ }
};
EMSCRIPTEN_SYMBOL(optionalMethod);
@@ -1120,6 +1126,14 @@ public:
void differentArguments(int i, double d, unsigned char f, double q, std::string s) {
return call<void>("differentArguments", i, d, f, q, s);
}
+
+ virtual void passShared(const std::shared_ptr<Derived>& p) override {
+ return call<void>("passShared", p);
+ }
+
+ virtual void passVal(const val& v) override {
+ return call<void>("passVal", v);
+ }
};
class ConcreteClass : public AbstractClass {
@@ -1196,6 +1210,15 @@ std::shared_ptr<PolySecondBase> passHeldAbstractClass(std::shared_ptr<HeldAbstra
return p;
}
+void passShared(AbstractClass& ac) {
+ auto p = std::make_shared<Derived>();
+ ac.passShared(p);
+}
+
+void passVal(AbstractClass& ac, val v) {
+ return ac.passVal(v);
+}
+
EMSCRIPTEN_BINDINGS(interface_tests) {
class_<AbstractClass>("AbstractClass")
.smart_ptr<std::shared_ptr<AbstractClass>>("shared_ptr<AbstractClass>")
@@ -1209,6 +1232,12 @@ EMSCRIPTEN_BINDINGS(interface_tests) {
}
))
.function("concreteMethod", &AbstractClass::concreteMethod)
+ .function("passShared", select_overload<void(AbstractClass&, const std::shared_ptr<Derived>&)>([](AbstractClass& self, const std::shared_ptr<Derived>& derived) {
+ self.AbstractClass::passShared(derived);
+ }))
+ .function("passVal", select_overload<void(AbstractClass&, const val&)>([](AbstractClass& self, const val& v) {
+ self.AbstractClass::passVal(v);
+ }))
;
function("getAbstractClass", &getAbstractClass);
@@ -1216,6 +1245,8 @@ EMSCRIPTEN_BINDINGS(interface_tests) {
function("callOptionalMethod", &callOptionalMethod);
function("callReturnsSharedPtrMethod", &callReturnsSharedPtrMethod);
function("callDifferentArguments", &callDifferentArguments);
+ function("passShared", &passShared);
+ function("passVal", &passVal);
class_<AbstractClassWithConstructor>("AbstractClassWithConstructor")
.allow_subclass<AbstractClassWithConstructorWrapper>("AbstractClassWithConstructorWrapper", constructor<std::string>())