From c75048adf764b9f14ed7a91dc46dfaee66dcbf3a Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 8 May 2014 21:41:34 -0700 Subject: If embind knows about a live JavaScript instance and it matches a raw pointer that gets returned, then return the JS instance. --- src/embind/embind.js | 72 +++++++++++++++++++++++++++++++++++++-------- tests/embind/embind.test.js | 7 ++--- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index ef16e952..f9bfa9e8 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -153,6 +153,30 @@ function _embind_repr(v) { } } +// raw pointer -> instance +var registeredInstances = {}; + +function registerInheritedInstance(ptr, instance) { + if (registeredInstances.hasOwnProperty(ptr)) { + throwBindingError('Tried to register registered instance: ' + ptr); + } else { + registeredInstances[ptr] = instance; + } +} + +function unregisterInheritedInstance(ptr) { + if (registeredInstances.hasOwnProperty(ptr)) { + delete registeredInstances[ptr]; + } else { + throwBindingError('Tried to unregister unregistered instance: ' + ptr); + } +} + +function getInheritedInstanceCount() { + return Object.keys(registeredInstances).length; +} +Module['getInheritedInstanceCount'] = getInheritedInstanceCount; + // typeID -> { toWireType: ..., fromWireType: ... } var registeredTypes = {}; @@ -1152,6 +1176,13 @@ RegisteredPointer.prototype['fromWireType'] = function fromWireType(ptr) { return null; } + var registeredInstance = registeredInstances[rawPointer]; + if (undefined !== registeredInstance) { + var rv = registeredInstance['clone'](); + this.destructor(ptr); + return rv; + } + function makeDefaultHandle() { if (this.isSmartPointer) { return makeClassHandle(this.registeredClass.instancePrototype, { @@ -1262,14 +1293,19 @@ ClassHandle.prototype['clone'] = function clone() { throwInstanceAlreadyDeleted(this); } - var clone = Object.create(Object.getPrototypeOf(this), { - $$: { - value: shallowCopy(this.$$), - } - }); + if (this.$$.preservePointerOnDelete) { + this.$$.count.value += 1; + return this; + } else { + var clone = Object.create(Object.getPrototypeOf(this), { + $$: { + value: shallowCopy(this.$$), + } + }); - clone.$$.count.value += 1; - return clone; + clone.$$.count.value += 1; + return clone; + } }; function runDestructor(handle) { @@ -1285,16 +1321,21 @@ ClassHandle.prototype['delete'] = function ClassHandle_delete() { if (!this.$$.ptr) { throwInstanceAlreadyDeleted(this); } + + // TODO: test for multiple deleteLater() on JS instance handle if (this.$$.deleteScheduled) { throwBindingError('Object already scheduled for deletion'); } this.$$.count.value -= 1; - if (0 === this.$$.count.value) { + var toDelete = 0 === this.$$.count.value; + if (toDelete) { runDestructor(this); } - this.$$.smartPtr = undefined; - this.$$.ptr = undefined; + if (toDelete || !this.$$.preservePointerOnDelete) { + this.$$.smartPtr = undefined; + this.$$.ptr = undefined; + } }; var deletionQueue = []; @@ -1359,7 +1400,9 @@ function RegisteredClass( function shallowCopy(o) { var rv = {}; for (var k in o) { - rv[k] = o[k]; + if (Object.prototype.hasOwnProperty.call(o, k)) { + rv[k] = o[k]; + } } return rv; } @@ -1764,16 +1807,21 @@ function __embind_create_inheriting_constructor(constructorName, wrapperType, pr }); // It's a little nasty that we're modifying the wrapper prototype here. + wrapperPrototype.__construct = function __construct() { var inner = baseConstructor.__$implement.apply( undefined, [this].concat(arraySlice.call(arguments))); + var $$ = inner.$$; + $$.preservePointerOnDelete = true; Object.defineProperty(this, '$$', { - value: inner.$$ + value: $$ }); + registerInheritedInstance($$.ptr, this); }; wrapperPrototype.__destruct = function __destruct() { + unregisterInheritedInstance(this.$$.ptr); }; ctor.prototype = Object.create(wrapperPrototype); diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index e77a8a43..b174b52d 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1776,6 +1776,7 @@ module({ }, __destruct: function() { calls.push("__destruct"); + this.__parent.__destruct.call(this); } }); var impl = new C; @@ -1786,7 +1787,6 @@ module({ assert.deepEqual(["__destruct"], calls); }); -/* does not pass yet test("if JavaScript implementation of interface is returned, don't wrap in new handle", function() { var parent = cm.HeldAbstractClass; var C = parent.extend("C", { @@ -1795,11 +1795,10 @@ module({ }); var impl = new C; var rv = cm.passHeldAbstractClass(impl); - assert.equal(impl, rv); - impl.delete(); + assert.equal(impl, rv); + rv.delete(); }); -*/ }); BaseFixture.extend("registration order", function() { -- cgit v1.2.3-18-g5258