diff options
-rwxr-xr-x | src/embind/embind.js | 236 | ||||
-rwxr-xr-x | system/include/emscripten/bind.h | 50 | ||||
-rwxr-xr-x | system/lib/embind/bind.cpp | 47 |
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.
|