aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/embind/embind.js300
-rwxr-xr-xsystem/include/emscripten/bind.h6
2 files changed, 169 insertions, 137 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index de87dceb..c1f9552d 100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -3,12 +3,14 @@
/*global FUNCTION_TABLE, HEAP32, HEAPU8*/
/*global Pointer_stringify*/
/*global __emval_register, _emval_handle_array, __emval_decref*/
-/*global ___getDynamicPointerType: false*/
/*global ___typeName:false*/
-/*global ___staticPointerCast: false*/
+var InternalError = Module.InternalError = extendError(Error, 'InternalError');
var BindingError = Module.BindingError = extendError(Error, 'BindingError');
-var CastError = Module.CastError = extendError(BindingError, 'CastError');
+
+function throwInternalError(value) {
+ throw new InternalError(value);
+}
function throwBindingError(value) {
throw new BindingError(value);
@@ -75,6 +77,9 @@ var registeredTypes = {};
// typeID -> [callback]
var awaitingDependencies = {};
+// class typeID -> {pointerType: ..., constPointerType: ...}
+var registeredPointers = {};
+
function registerType(rawType, registeredInstance) {
var name = registeredInstance.name;
if (!rawType) {
@@ -144,17 +149,6 @@ function requireRegisteredType(rawType, humanName) {
return impl;
}
-function staticPointerCast(from, fromType, toType) {
- if (!from) {
- return from;
- }
- var to = ___staticPointerCast(from, fromType, toType);
- if (to <= 0) {
- throw new CastError("Pointer conversion from " + typeName(fromType) + " to " + typeName(toType) + " is not available");
- }
- return to;
-}
-
function __embind_register_void(rawType, name) {
name = Pointer_stringify(name);
registerType(rawType, {
@@ -468,7 +462,7 @@ function __embind_register_struct_field(
});
}
-// I guarantee there is a way to simplify the following data structure.
+// todo: I guarantee there is a way to simplify the following data structure.
function RegisteredPointer(
name,
rawType,
@@ -477,6 +471,7 @@ function RegisteredPointer(
isReference,
isConst,
isSmartPointer,
+ pointeeType,
sharingPolicy,
rawGetPointee,
rawConstructor,
@@ -490,6 +485,7 @@ function RegisteredPointer(
this.isReference = isReference;
this.isConst = isConst;
this.isSmartPointer = isSmartPointer;
+ this.pointeeType = pointeeType;
this.sharingPolicy = sharingPolicy;
this.rawGetPointee = rawGetPointee;
this.rawConstructor = rawConstructor;
@@ -497,14 +493,16 @@ function RegisteredPointer(
this.rawDestructor = rawDestructor;
}
-RegisteredPointer.prototype.isPolymorphic = function() {
- return this.registeredClass.isPolymorphic;
-};
-
RegisteredPointer.prototype.toWireType = function(destructors, handle) {
var self = this;
function throwCannotConvert() {
- throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + self.name);
+ var name;
+ if (handle.$$.smartPtrType) {
+ name = handle.$$.smartPtrType.name;
+ } else {
+ name = handle.$$.ptrType.name;
+ }
+ throwBindingError('Cannot convert argument of type ' + name + ' to parameter type ' + self.name);
}
if (handle === null) {
@@ -537,7 +535,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) {
switch (this.sharingPolicy) {
case 0: // NONE
// no upcasting
- if (handle.$$.ptrType === this) {
+ if (handle.$$.smartPtrType === this) {
ptr = handle.$$.smartPtr;
} else {
throwCannotConvert();
@@ -549,7 +547,7 @@ RegisteredPointer.prototype.toWireType = function(destructors, handle) {
break;
case 2: // BY_EMVAL
- if (handle.$$.ptrType === this) {
+ if (handle.$$.smartPtrType === this) {
ptr = handle.$$.smartPtr;
} else {
var clonedHandle = handle.clone();
@@ -583,68 +581,133 @@ RegisteredPointer.prototype.destructor = function(ptr) {
}
};
-RegisteredPointer.prototype.getDynamicRawPointerType = function(ptr) {
- var type = null;
- if (this.isPolymorphic()) {
- if (this.rawGetPointee) {
- type = ___getDynamicPointerType(this.rawGetPointee(ptr));
- } else {
- type = ___getDynamicPointerType(ptr);
- }
+RegisteredPointer.prototype.fromWireType = function(ptr) {
+ // ptr is a raw pointer (or a raw smartpointer)
+
+ // rawPointer is a maybe-null raw pointer
+ var rawPointer = this.getPointee(ptr);
+ if (!rawPointer) {
+ this.destructor(ptr);
+ return null;
}
- return type;
-};
-RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) {
- var downcastType = null;
- var type = this.getDynamicRawPointerType(ptr);
- if (type && type !== this.registeredClass.rawType) {
- var derivation = Module.__getDerivationPath(type, this.registeredClass.rawType);
- for (var i = 0; i < derivation.size(); i++) {
- downcastType = registeredTypes[derivation.get(i)];
- if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) {
- break;
- }
+ function makeDefaultHandle() {
+ if (this.isSmartPointer) {
+ return makeClassHandle(this.Handle.prototype, {
+ ptrType: this.pointeeType,
+ ptr: rawPointer,
+ smartPtrType: this,
+ smartPtr: ptr,
+ });
+ } else {
+ return makeClassHandle(this.Handle.prototype, {
+ ptrType: this,
+ ptr: ptr,
+ });
}
- derivation.delete();
}
- return downcastType;
-};
-RegisteredPointer.prototype.fromWireType = function(ptr) { // ptr is a raw pointer (or a raw smartpointer)
- function makeHandle(registeredType, ptr) {
- return new registeredType.Handle(registeredType, ptr);
+ var actualType = this.registeredClass.getActualType(rawPointer);
+ var registeredPointerRecord = registeredPointers[actualType];
+ if (!registeredPointerRecord) {
+ return makeDefaultHandle.call(this);
}
- var handle;
- if (!this.getPointee(ptr)) {
- this.destructor(ptr);
- return null;
+ var toType;
+ if (this.isConst) {
+ toType = registeredPointerRecord.constPointerType;
+ } else {
+ toType = registeredPointerRecord.pointerType;
}
- var toType = this.getDynamicDowncastType(ptr);
- if (toType) {
- if (this.isSmartPointer) {
- handle = makeHandle(toType.smartPointerType, ptr);
- } else {
- handle = makeHandle(toType, ptr);
- }
- handle.$$.ptr = staticPointerCast(handle.$$.ptr, this.registeredClass.rawType, toType.rawType);
+ var dp = downcastPointer(
+ rawPointer,
+ this.registeredClass,
+ toType.registeredClass);
+ if (dp === null) {
+ return makeDefaultHandle.call(this);
+ }
+ if (this.isSmartPointer) {
+ return makeClassHandle(toType.Handle.prototype, {
+ ptrType: toType,
+ ptr: dp,
+ smartPtrType: this,
+ smartPtr: ptr,
+ });
} else {
- handle = makeHandle(this, ptr);
+ return makeClassHandle(toType.Handle.prototype, {
+ ptrType: toType,
+ ptr: dp,
+ });
}
- return handle;
};
+function makeClassHandle(prototype, record) {
+ if (!record.ptrType || !record.ptr) {
+ throwInternalError('makeClassHandle requires ptr and ptrType');
+ }
+ var hasSmartPtrType = !!record.smartPtrType;
+ var hasSmartPtr = !!record.smartPtr;
+ if (hasSmartPtrType !== hasSmartPtr) {
+ throwInternalError('Both smartPtrType and smartPtr must be specified');
+ }
+ record.count = { value: 1 };
+ return Object.create(prototype, {
+ '$$': {
+ value: record,
+ },
+ });
+}
+
// root of all pointer and smart pointer handles in embind
function ClassHandle() {
}
+function getInstanceTypeName(handle) {
+ return handle.$$.ptrType.registeredClass.name;
+}
+
+ClassHandle.prototype.clone = function() {
+ if (!this.$$.ptr) {
+ throwBindingError(getInstanceTypeName(this) + ' instance already deleted');
+ }
+
+ var clone = Object.create(Object.getPrototypeOf(this), {
+ '$$': {
+ value: shallowCopy(this.$$),
+ }
+ });
+
+ clone.$$.count.value += 1;
+ return clone;
+};
+
+function runDestructor(handle) {
+ var $$ = handle.$$;
+ if ($$.smartPtr) {
+ $$.smartPtrType.rawDestructor($$.smartPtr);
+ } else {
+ $$.ptrType.registeredClass.rawDestructor($$.ptr);
+ }
+}
+
+ClassHandle.prototype['delete'] = function() {
+ if (!this.$$.ptr) {
+ throwBindingError(getInstanceTypeName(this) + ' instance already deleted');
+ }
+
+ this.$$.count.value -= 1;
+ if (0 === this.$$.count.value) {
+ runDestructor(this);
+ }
+ this.$$.smartPtr = undefined;
+ this.$$.ptr = undefined;
+};
+
function RegisteredClass(
name,
rawType,
constructor,
- isPolymorphic,
- baseClassRawType,
+ rawDestructor,
baseClass,
getActualType,
upcast,
@@ -653,8 +716,7 @@ function RegisteredClass(
this.name = name;
this.rawType = rawType;
this.constructor = constructor;
- this.isPolymorphic = isPolymorphic;
- this.baseClassRawType = baseClassRawType;
+ this.rawDestructor = rawDestructor;
this.baseClass = baseClass;
this.getActualType = getActualType;
this.upcast = upcast;
@@ -677,7 +739,6 @@ function __embind_register_class(
getActualType,
upcast,
downcast,
- isPolymorphic,
name,
rawDestructor
) {
@@ -713,46 +774,20 @@ function __embind_register_class(
});
});
+ Handle.prototype = Object.create(basePrototype, {
+ constructor: { value: Handle },
+ });
+
var registeredClass = new RegisteredClass(
name,
rawType,
Handle,
- isPolymorphic,
- baseClassRawType,
+ rawDestructor,
baseClass,
getActualType,
upcast,
downcast);
- Handle.prototype = Object.create(basePrototype, {
- constructor: { value: Handle },
- });
- Handle.prototype.clone = function() {
- if (!this.$$.ptr) {
- throwBindingError(type.name + ' instance already deleted');
- }
-
- var clone = Object.create(Handle.prototype);
- Object.defineProperty(clone, '$$', {
- value: shallowCopy(this.$$),
- });
-
- clone.$$.count.value += 1;
- return clone;
- };
-
- Handle.prototype['delete'] = function() {
- if (!this.$$.ptr) {
- throwBindingError(type.name + ' instance already deleted');
- }
-
- this.$$.count.value -= 1;
- if (0 === this.$$.count.value) {
- rawDestructor(this.$$.ptr);
- }
- this.$$.ptr = undefined;
- };
-
// todo: clean this up!
var type = new RegisteredPointer(
name,
@@ -764,23 +799,30 @@ function __embind_register_class(
false);
registerType(rawType, type);
- registerType(rawPointerType, new RegisteredPointer(
+ var pointerType = new RegisteredPointer(
name + '*',
rawPointerType,
registeredClass,
Handle,
false,
false,
- false));
+ false);
+ registerType(rawPointerType, pointerType);
- registerType(rawConstPointerType, new RegisteredPointer(
+ var constPointerType = new RegisteredPointer(
name + ' const*',
rawConstPointerType,
registeredClass,
Handle,
false,
true,
- false));
+ false);
+ registerType(rawConstPointerType, constPointerType);
+
+ registeredPointers[rawType] = {
+ pointerType: pointerType,
+ constPointerType: constPointerType
+ };
type.constructor = createNamedFunction(legalFunctionName, function() {
if (Object.getPrototypeOf(this) !== Handle.prototype) {
@@ -832,6 +874,18 @@ function __embind_register_class_constructor(
});
}
+function downcastPointer(ptr, ptrClass, desiredClass) {
+ if (ptrClass === desiredClass) {
+ return ptr;
+ }
+ if (undefined === desiredClass.baseClass) {
+ return null; // no conversion
+ }
+ // O(depth) stack space used
+ return desiredClass.downcast(
+ downcastPointer(ptr, ptrClass, desiredClass.baseClass));
+}
+
function upcastPointer(ptr, ptrClass, desiredClass) {
while (ptrClass !== desiredClass) {
ptr = ptrClass.upcast(ptr);
@@ -983,46 +1037,23 @@ function __embind_register_smart_ptr(
whenDependentTypesAreResolved([rawPointeeType], function(pointeeType) {
pointeeType = pointeeType[0];
- var Handle = createNamedFunction(makeLegalFunctionName(name), function(ptrType, ptr) {
+ var Handle = createNamedFunction(makeLegalFunctionName(name), function(smartPtrType, smartPtr, ptrType, ptr) {
+ if (arguments.length !== 4) {
+ throwBindingError("internal error");
+ }
Object.defineProperty(this, '$$', {
value: {
- ptrType: ptrType,
count: {value: 1},
- smartPtr: ptr,
- ptr: rawGetPointee(ptr),
+ ptrType: ptrType,
+ ptr: ptr,
+ smartPtrType: registeredPointer,
+ smartPtr: smartPtr,
},
});
});
Handle.prototype = Object.create(pointeeType.Handle.prototype);
- Handle.prototype.clone = function() {
- if (!this.$$.ptr) {
- throwBindingError(pointeeType.name + ' instance already deleted');
- }
-
- var clone = Object.create(Handle.prototype);
- Object.defineProperty(clone, '$$', {
- value: shallowCopy(this.$$),
- });
-
- clone.$$.count.value += 1;
- return clone;
- };
-
- Handle.prototype['delete'] = function() {
- if (!this.$$.ptr) {
- throwBindingError(pointeeType.name + ' instance already deleted');
- }
-
- this.$$.count.value -= 1;
- if (0 === this.$$.count.value) {
- rawDestructor(this.$$.smartPtr);
- }
- this.$$.smartPtr = undefined;
- this.$$.ptr = undefined;
- };
-
var registeredPointer = new RegisteredPointer(
name,
rawType,
@@ -1030,14 +1061,15 @@ function __embind_register_smart_ptr(
Handle,
false,
false,
+ // smart pointer properties
true,
+ pointeeType,
sharingPolicy,
rawGetPointee,
rawConstructor,
rawShare,
rawDestructor);
registerType(rawType, registeredPointer);
- pointeeType.smartPointerType = registeredPointer;
});
}
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index cd208d37..a1b2a015 100755
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -117,7 +117,6 @@ namespace emscripten {
GenericFunction getActualType,
GenericFunction upcast,
GenericFunction downcast,
- bool isPolymorphic,
const char* className,
GenericFunction destructor);
@@ -650,9 +649,11 @@ namespace emscripten {
}
};
+ // NOTE: this returns the class type, not the pointer type
template<typename T>
inline TYPEID getActualType(T* ptr) {
- return reinterpret_cast<TYPEID>(&typeid(ptr));
+ assert(ptr);
+ return reinterpret_cast<TYPEID>(&typeid(*ptr));
};
}
@@ -720,7 +721,6 @@ namespace emscripten {
reinterpret_cast<GenericFunction>(&getActualType<ClassType>),
BaseSpecifier::template getUpcaster<ClassType>(),
BaseSpecifier::template getDowncaster<ClassType>(),
- std::is_polymorphic<ClassType>::value, // TODO: may not be necessary
name,
reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>));
}