aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/embind/embind.js236
-rwxr-xr-xsystem/include/emscripten/bind.h50
-rwxr-xr-xsystem/lib/embind/bind.cpp47
3 files changed, 149 insertions, 184 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 4086e2a5..f970317e 100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -67,127 +67,58 @@ function _embind_repr(v) {
}
}
-var typeRegistry = {};
-var deferredRegistrations = [];
var baseClasses = {}; // rawType -> rawBaseType
-function requestDeferredRegistration(registrationFunction) {
- deferredRegistrations.push(registrationFunction);
-}
-
-function performDeferredRegistrations(){
- while(deferredRegistrations.length > 0) {
- var registrationFunction = deferredRegistrations.shift();
- registrationFunction();
- }
-}
-
-function createInheritedFunctionOrProperty(name, type, nameInBaseClass, baseClassType) {
- function upcastingWrapper(method) {
- return function() {
- var baseClassPtr = ___staticPointerCast(this.$$.ptr, type.rawType, baseClassType.rawType);
- if (baseClassPtr === this.$$.ptr) {
- return method.apply(this, arguments);
- } else {
- var handle = this.clone();
- try {
- handle.$$.ptr = baseClassPtr;
- return method.apply(handle, arguments);
- } finally {
- handle.delete();
- }
- }
- };
- }
- var baseClassPrototype = baseClassType.Handle.prototype;
- if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'field') {
- var baseClassDescriptor = Object.getOwnPropertyDescriptor(baseClassPrototype, nameInBaseClass);
- Object.defineProperty(type.Handle.prototype, name, {
- enumerable: true,
- get: upcastingWrapper(baseClassDescriptor.get),
- set: upcastingWrapper(baseClassDescriptor.set)
- });
- type.Handle.memberType[name] = 'field';
- } else if (baseClassPrototype.constructor.memberType[nameInBaseClass] === 'method') {
- var baseClassMethod = baseClassPrototype[nameInBaseClass];
- type.Handle.prototype[name] = createNamedFunction(name, upcastingWrapper(baseClassMethod));
- type.Handle.memberType[name] = 'method';
- }
-}
-
-function collectRegisteredBaseClasses(type) {
- var rawType = type.rawType;
- if (undefined === rawType) {
- return [];
- }
- var rawBaseType = baseClasses[rawType];
- if (!rawBaseType) {
- return [];
- }
- var baseType = typeRegistry[rawBaseType];
- if (baseType) {
- return [baseType];
- } else {
- return collectRegisteredBaseClasses(baseType);
- }
-}
+// typeID -> { toWireType: ..., fromWireType: ... }
+var registeredTypes = {};
-function resolveType(type) {
- if (!type.resolved) {
- var baseClassType, name, baseProto;
- var inheritedNames = {};
- var baseTypes = collectRegisteredBaseClasses(type);
- for (var i = 0; i < baseTypes.length; i++) {
- var baseType = baseTypes[i];
- resolveType(baseType);
- baseProto = baseType.Handle.prototype;
- for (name in baseProto) {
- if (baseProto.hasOwnProperty(name) && baseType.Handle.memberType[name]) {
- if (!(name in inheritedNames)) {
- inheritedNames[name] = [];
- }
- inheritedNames[name].push(baseType);
- }
- }
- }
- for (name in inheritedNames) {
- if (inheritedNames.hasOwnProperty(name)) {
- if (!type.Handle.prototype.hasOwnProperty(name) && inheritedNames[name].length === 1) {
- baseClassType = inheritedNames[name][0];
- createInheritedFunctionOrProperty(name, type, name, baseClassType);
- }
- }
- }
- type.resolved = true;
- }
-}
-
-function resolveBindings() {
- performDeferredRegistrations();
- for (var rawType in typeRegistry) {
- if (typeRegistry.hasOwnProperty(rawType)) {
- resolveType(typeRegistry[rawType]);
- }
- }
-}
+// typeID -> [callback]
+var awaitingDependencies = {};
function registerType(rawType, registeredInstance) {
var name = registeredInstance.name;
if (!rawType) {
throwBindingError('type "' + name + '" must have a positive integer typeid pointer');
}
- if (typeRegistry.hasOwnProperty(rawType)) {
+ if (registeredTypes.hasOwnProperty(rawType)) {
throwBindingError("Cannot register type '" + name + "' twice");
}
- typeRegistry[rawType] = registeredInstance;
+
+ registeredTypes[rawType] = registeredInstance;
+
+ if (awaitingDependencies.hasOwnProperty(rawType)) {
+ var callbacks = awaitingDependencies[rawType];
+ delete awaitingDependencies[rawType];
+ callbacks.forEach(function(cb) {
+ cb();
+ });
+ }
}
-function requireRegisteredType(rawType, humanName) {
- var impl = typeRegistry[rawType];
- if (undefined === impl) {
- throwBindingError(humanName + " has unknown type " + typeName(rawType));
+function whenDependentTypesAreResolved(dependentTypes, onComplete) {
+ var typeConverters = new Array(dependentTypes.length);
+ var unregisteredTypes = [];
+ var registered = 0;
+ dependentTypes.forEach(function(dt, i) {
+ if (registeredTypes.hasOwnProperty(dt)) {
+ typeConverters[i] = registeredTypes[dt];
+ } else {
+ unregisteredTypes.push(dt);
+ if (!awaitingDependencies.hasOwnProperty(dt)) {
+ awaitingDependencies[dt] = [];
+ }
+ awaitingDependencies[dt].push(function() {
+ typeConverters[i] = registeredTypes[dt];
+ ++registered;
+ if (registered === unregisteredTypes.length) {
+ onComplete(typeConverters);
+ }
+ });
+ }
+ });
+ if (0 === unregisteredTypes.length) {
+ onComplete(typeConverters);
}
- return impl;
}
function typeName(rawType) {
@@ -205,17 +136,27 @@ function heap32VectorToArray(count, firstElement) {
return array;
}
+function requireRegisteredType(rawType, humanName) {
+ var impl = registeredTypes[rawType];
+ if (undefined === impl) {
+ throwBindingError(humanName + " has unknown type " + typeName(rawType));
+ }
+ return impl;
+}
+
+/*
function requireArgumentTypes(rawArgTypes, name) {
var argTypes = [];
for (var i = 0; i < rawArgTypes.length; ++i) {
- if (i === 0) {
- argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " return value");
- } else {
- argTypes[i] = requireRegisteredType(rawArgTypes[i], name + " parameter " + i);
- }
+ argTypes[i] = requireRegisteredType(
+ rawArgTypes[i],
+ i === 0 ?
+ name + " return value" :
+ name + " parameter " + i);
}
return argTypes;
}
+*/
function staticPointerCast(from, fromType, toType) {
if (!from) {
@@ -362,11 +303,10 @@ function makeInvoker(name, argCount, argTypes, invoker, fn) {
}
function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) {
- var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
+ var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
name = Pointer_stringify(name);
rawInvoker = FUNCTION_TABLE[rawInvoker];
- requestDeferredRegistration(function() {
- var argTypes = requireArgumentTypes(rawArgTypes, name);
+ whenDependentTypesAreResolved(argTypes, function(argTypes) {
exposePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn));
});
}
@@ -425,10 +365,11 @@ function __embind_register_tuple_element(
getter = FUNCTION_TABLE[getter];
setter = FUNCTION_TABLE[setter];
memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
+ var tupleType = requireRegisteredType(rawTupleType, 'tuple');
+
// TODO: this could register elements out of order
- requestDeferredRegistration(function() {
- var tupleType = requireRegisteredType(rawTupleType, 'tuple');
- var type = requireRegisteredType(rawType, "element " + tupleType.name + "[" + tupleType.elements.length + "]");
+ whenDependentTypesAreResolved([rawType], function(type) {
+ type = type[0];
tupleType.elements.push({
read: function(ptr) {
return type.fromWireType(getter(ptr, memberPointer));
@@ -452,13 +393,14 @@ function __embind_register_tuple_element_accessor(
setterSize,
setter
) {
+ var tupleType = requireRegisteredType(rawTupleType, 'tuple');
rawStaticGetter = FUNCTION_TABLE[rawStaticGetter];
getter = copyMemberPointer(getter, getterSize);
rawStaticSetter = FUNCTION_TABLE[rawStaticSetter];
setter = copyMemberPointer(setter, setterSize);
- requestDeferredRegistration(function() {
- var tupleType = requireRegisteredType(rawTupleType, 'tuple');
- var elementType = requireRegisteredType(rawElementType, "element " + tupleType.name + "[" + tupleType.elements.length + "]");
+
+ whenDependentTypesAreResolved([rawElementType], function(elementType) {
+ elementType = elementType[0];
tupleType.elements.push({
read: function(ptr) {
return elementType.fromWireType(rawStaticGetter(ptr, HEAP32[getter >> 2]));
@@ -526,14 +468,14 @@ function __embind_register_struct_field(
memberPointerSize,
memberPointer
) {
+ var structType = requireRegisteredType(rawStructType, 'struct');
fieldName = Pointer_stringify(fieldName);
rawGetter = FUNCTION_TABLE[rawGetter];
rawSetter = FUNCTION_TABLE[rawSetter];
memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
// TODO: this could register elements out of order
- requestDeferredRegistration(function() {
- var structType = requireRegisteredType(rawStructType, 'struct');
- var fieldType = requireRegisteredType(rawFieldType, 'field "' + structType.name + '.' + fieldName + '"');
+ whenDependentTypesAreResolved([rawFieldType], function(fieldType) {
+ fieldType = fieldType[0];
structType.fields[fieldName] = {
read: function(ptr) {
return fieldType.fromWireType(rawGetter(ptr, memberPointer));
@@ -638,7 +580,7 @@ RegisteredPointer.prototype.getDynamicDowncastType = function(ptr) {
if (type && type !== this.pointeeType.rawType) {
var derivation = Module.__getDerivationPath(type, this.pointeeType.rawType);
for (var i = 0; i < derivation.size(); i++) {
- downcastType = typeRegistry[derivation.get(i)];
+ downcastType = registeredTypes[derivation.get(i)];
if (downcastType && (!this.isSmartPointer || downcastType.smartPointerType)) {
break;
}
@@ -758,18 +700,34 @@ function __embind_register_class(
rawPointerType,
rawConstPointerType,
baseClassRawType,
+ upcast,
+ downcast,
isPolymorphic,
name,
rawDestructor
) {
name = Pointer_stringify(name);
rawDestructor = FUNCTION_TABLE[rawDestructor];
+ upcast = FUNCTION_TABLE[upcast];
+ downcast = FUNCTION_TABLE[downcast];
+ var basePrototype;
if (baseClassRawType) {
baseClasses[rawType] = baseClassRawType;
+
+ // TODO: allow registration of base after derived
+ var base = requireRegisteredType(baseClassRawType, 'base class');
+ basePrototype = base.Handle.prototype;
+ } else {
+ basePrototype = ClassHandle.prototype;
}
- var registeredClass = new RegisteredClass(name, isPolymorphic, baseClassRawType);
+ var registeredClass = new RegisteredClass(
+ name,
+ isPolymorphic,
+ baseClassRawType,
+ upcast,
+ downcast);
var Handle = createNamedFunction(name, function(ptr) {
Object.defineProperty(this, '$$', {
@@ -781,7 +739,7 @@ function __embind_register_class(
});
});
- Handle.prototype = Object.create(ClassHandle.prototype, {
+ Handle.prototype = Object.create(basePrototype, {
constructor: { value: Handle },
});
Handle.prototype.clone = function() {
@@ -814,7 +772,6 @@ function __embind_register_class(
}
this.$$.ptr = undefined;
};
- Handle.memberType = {};
// todo: clean this up!
var type = new RegisteredPointer(
@@ -867,13 +824,12 @@ function __embind_register_class_constructor(
invoker,
rawConstructor
) {
+ var classType = requireRegisteredType(rawClassType, 'class');
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
invoker = FUNCTION_TABLE[invoker];
- requestDeferredRegistration(function() {
- var classType = requireRegisteredType(rawClassType, 'class');
+ whenDependentTypesAreResolved(rawArgTypes, function(argTypes) {
var humanName = 'constructor ' + classType.name;
- var argTypes = requireArgumentTypes(rawArgTypes, humanName);
classType.constructor.body = function() {
if (arguments.length !== argCount - 1) {
throwBindingError(humanName + ' called with ' + arguments.length + ' arguments, expected ' + (argCount-1));
@@ -902,14 +858,13 @@ function __embind_register_class_method(
memberFunctionSize,
memberFunction
) {
+ var classType = requireRegisteredType(rawClassType, 'class');
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
methodName = Pointer_stringify(methodName);
rawInvoker = FUNCTION_TABLE[rawInvoker];
memberFunction = copyMemberPointer(memberFunction, memberFunctionSize);
- requestDeferredRegistration(function() {
- var classType = requireRegisteredType(rawClassType, 'class');
+ whenDependentTypesAreResolved(rawArgTypes, function(argTypes) {
var humanName = classType.name + '.' + methodName;
- var argTypes = requireArgumentTypes(rawArgTypes, 'method ' + humanName);
classType.Handle.prototype[methodName] = function() {
if (!this.$$.ptr) {
throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object');
@@ -934,7 +889,6 @@ function __embind_register_class_method(
runDestructors(destructors);
return rv;
};
- classType.Handle.memberType[methodName] = "method";
});
}
@@ -946,13 +900,12 @@ function __embind_register_class_classmethod(
rawInvoker,
fn
) {
+ var classType = requireRegisteredType(rawClassType, 'class');
var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr);
methodName = Pointer_stringify(methodName);
rawInvoker = FUNCTION_TABLE[rawInvoker];
- requestDeferredRegistration(function() {
- var classType = requireRegisteredType(rawClassType, 'class');
+ whenDependentTypesAreResolved(rawArgTypes, function(argTypes) {
var humanName = classType.name + '.' + methodName;
- var argTypes = requireArgumentTypes(rawArgTypes, 'classmethod ' + humanName);
classType.constructor[methodName] = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn);
});
}
@@ -966,14 +919,14 @@ function __embind_register_class_field(
memberPointerSize,
memberPointer
) {
+ var classType = requireRegisteredType(rawClassType, 'class');
fieldName = Pointer_stringify(fieldName);
getter = FUNCTION_TABLE[getter];
setter = FUNCTION_TABLE[setter];
memberPointer = copyMemberPointer(memberPointer, memberPointerSize);
- requestDeferredRegistration(function() {
- var classType = requireRegisteredType(rawClassType, 'class');
+ whenDependentTypesAreResolved([rawFieldType], function(fieldType) {
var humanName = classType.name + '.' + fieldName;
- var fieldType = requireRegisteredType(rawFieldType, 'field ' + humanName);
+ fieldType = fieldType[0];
Object.defineProperty(classType.Handle.prototype, fieldName, {
get: function() {
if (!this.$$.ptr) {
@@ -991,7 +944,6 @@ function __embind_register_class_field(
},
enumerable: true
});
- classType.Handle.memberType[fieldName] = "field";
});
}
diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h
index 24a7bf71..e8cedbe4 100755
--- a/system/include/emscripten/bind.h
+++ b/system/include/emscripten/bind.h
@@ -106,6 +106,8 @@ namespace emscripten {
TYPEID pointerType,
TYPEID constPointerType,
TYPEID baseClassType,
+ GenericFunction upcast,
+ GenericFunction downcast,
bool isPolymorphic,
const char* className,
GenericFunction destructor);
@@ -159,8 +161,6 @@ namespace emscripten {
GenericFunction destructor);
}
- extern void registerStandardTypes();
-
class BindingsDefinition {
public:
template<typename Function>
@@ -248,9 +248,6 @@ namespace emscripten {
template<typename ReturnType, typename... Args, typename... Policies>
void function(const char* name, ReturnType (*fn)(Args...), Policies...) {
using namespace internal;
-
- registerStandardTypes();
-
typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args;
_embind_register_function(
name,
@@ -415,7 +412,6 @@ namespace emscripten {
class value_tuple {
public:
value_tuple(const char* name) {
- internal::registerStandardTypes();
internal::_embind_register_tuple(
internal::TypeID<ClassType>::get(),
name,
@@ -501,7 +497,6 @@ namespace emscripten {
class value_struct {
public:
value_struct(const char* name) {
- internal::registerStandardTypes();
internal::_embind_register_struct(
internal::TypeID<ClassType>::get(),
name,
@@ -562,7 +557,6 @@ namespace emscripten {
using namespace internal;
typedef typename smart_ptr_trait<PointerType>::element_type PointeeType;
- registerStandardTypes();
_embind_register_smart_ptr(
TypeID<PointerType>::get(),
TypeID<PointeeType>::get(),
@@ -613,27 +607,52 @@ namespace emscripten {
namespace internal {
struct NoBaseClass {
+ template<typename ClassType>
+ static void verify() {
+ }
+
static TYPEID get() {
- return 0;
+ return nullptr;
}
template<typename ClassType>
- static void verify() {
+ static GenericFunction getUpcaster() {
+ return nullptr;
+ }
+
+ template<typename ClassType>
+ static GenericFunction getDowncaster() {
+ return nullptr;
}
};
}
template<typename BaseClass>
struct base {
- static internal::TYPEID get() {
- return internal::TypeID<BaseClass>::get();
- }
-
template<typename ClassType>
static void verify() {
static_assert(!std::is_same<ClassType, BaseClass>::value, "Base must not have same type as class");
static_assert(std::is_base_of<BaseClass, ClassType>::value, "Derived class must derive from base");
}
+
+ static internal::TYPEID get() {
+ return internal::TypeID<BaseClass>::get();
+ }
+
+ template<typename ClassType>
+ static internal::GenericFunction getUpcaster() {
+ return reinterpret_cast<internal::GenericFunction>(&convertPointer<ClassType, BaseClass>);
+ }
+
+ template<typename ClassType>
+ static internal::GenericFunction getDowncaster() {
+ return reinterpret_cast<internal::GenericFunction>(&convertPointer<BaseClass, ClassType>);
+ }
+
+ template<typename From, typename To>
+ static To* convertPointer(From* ptr) {
+ return static_cast<To*>(ptr);
+ }
};
template<typename ClassType, typename BaseSpecifier = internal::NoBaseClass>
@@ -644,12 +663,13 @@ namespace emscripten {
BaseSpecifier::template verify<ClassType>();
- registerStandardTypes();
_embind_register_class(
TypeID<ClassType>::get(),
TypeID<AllowedRawPointer<ClassType>>::get(),
TypeID<AllowedRawPointer<const ClassType>>::get(),
BaseSpecifier::get(),
+ BaseSpecifier::template getUpcaster<ClassType>(),
+ BaseSpecifier::template getDowncaster<ClassType>(),
std::is_polymorphic<ClassType>::value,
name,
reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>));
diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp
index cbff7cf1..6c792f78 100755
--- a/system/lib/embind/bind.cpp
+++ b/system/lib/embind/bind.cpp
@@ -66,33 +66,6 @@ namespace __cxxabiv1 {
namespace emscripten {
namespace internal {
- void registerStandardTypes() {
- static bool first = true;
- if (first) {
- first = false;
-
- _embind_register_void(TypeID<void>::get(), "void");
-
- _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
-
- _embind_register_integer(TypeID<char>::get(), "char");
- _embind_register_integer(TypeID<signed char>::get(), "signed char");
- _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char");
- _embind_register_integer(TypeID<signed short>::get(), "short");
- _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short");
- _embind_register_integer(TypeID<signed int>::get(), "int");
- _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int");
- _embind_register_integer(TypeID<signed long>::get(), "long");
- _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long");
-
- _embind_register_float(TypeID<float>::get(), "float");
- _embind_register_float(TypeID<double>::get(), "double");
-
- _embind_register_cstring(TypeID<std::string>::get(), "std::string");
- _embind_register_emval(TypeID<val>::get(), "emscripten::val");
- }
- }
-
// __getDerivationPath returns an array of type_info pointers describing the derivation chain starting with
// the derived type and proceeding toward (and ending with) the base type. Types are only included if they
// appear on all possible derivation paths.
@@ -216,6 +189,26 @@ namespace emscripten {
}
EMSCRIPTEN_BINDINGS(([]() {
+ _embind_register_void(TypeID<void>::get(), "void");
+
+ _embind_register_bool(TypeID<bool>::get(), "bool", true, false);
+
+ _embind_register_integer(TypeID<char>::get(), "char");
+ _embind_register_integer(TypeID<signed char>::get(), "signed char");
+ _embind_register_integer(TypeID<unsigned char>::get(), "unsigned char");
+ _embind_register_integer(TypeID<signed short>::get(), "short");
+ _embind_register_integer(TypeID<unsigned short>::get(), "unsigned short");
+ _embind_register_integer(TypeID<signed int>::get(), "int");
+ _embind_register_integer(TypeID<unsigned int>::get(), "unsigned int");
+ _embind_register_integer(TypeID<signed long>::get(), "long");
+ _embind_register_integer(TypeID<unsigned long>::get(), "unsigned long");
+
+ _embind_register_float(TypeID<float>::get(), "float");
+ _embind_register_float(TypeID<double>::get(), "double");
+
+ _embind_register_cstring(TypeID<std::string>::get(), "std::string");
+ _embind_register_emval(TypeID<val>::get(), "emscripten::val");
+
// We bind __getDerivationPath in order to take advantage of the std::vector to Javascript array
// conversion for the return value. This has the unfortunate side-effect of exposing it to third party
// developers, but perhaps the double underscore will scare them away from calling it.