diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-04-25 15:47:50 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-04-25 15:47:50 -0700 |
commit | 5940f5fc55f36e55466716514945cb6ac54c4634 (patch) | |
tree | 9460c320606b3582b24d24876cebe6bd8f685d77 | |
parent | ffa17762a625018c557a39056ac8eb0b54251694 (diff) | |
parent | 9a530d0e76ea951f761d93ce3aa739b5605acb25 (diff) |
Merge pull request #2287 from chadaustin/embind-fastcomp-asm.js
Enable embind in fastcomp/asm.js
-rwxr-xr-x | emcc | 6 | ||||
-rw-r--r-- | src/embind/embind.js | 114 | ||||
-rw-r--r-- | system/include/emscripten/bind.h | 305 | ||||
-rw-r--r-- | tests/test_core.py | 4 | ||||
-rw-r--r-- | tests/test_other.py | 1 |
5 files changed, 324 insertions, 106 deletions
@@ -1224,11 +1224,6 @@ try: value = value.replace('\\\\', '/').replace('\\', '/') # Convert backslash paths to forward slashes on Windows as well, since the JS compiler otherwise needs the backslashes escaped (alternative is to escape all input paths passing to JS, which feels clumsier to read) exec('shared.Settings.' + key + ' = ' + value) - # Apply effects from settings - if bind and shared.Settings.ASM_JS: - logging.warning('disabling asm.js since embind is not ready for it yet') - shared.Settings.ASM_JS = 0 - fastcomp = os.environ.get('EMCC_FAST_COMPILER') != '0' if fastcomp: @@ -1245,7 +1240,6 @@ try: assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten' assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2' assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' - assert not bind, 'embind not supported in fastcomp yet' assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet' assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp' diff --git a/src/embind/embind.js b/src/embind/embind.js index 6ec07cd9..bb979365 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,4 +1,4 @@ -/*global Module*/ +/*global Module, asm*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/ /*global readLatin1String*/ @@ -622,10 +622,6 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp var isClassMethodFunc = (argTypes[1] !== null && classType !== null); - if (!isClassMethodFunc && !FUNCTION_TABLE[cppTargetFunc]) { - throwBindingError('Global function '+humanName+' is not defined!'); - } - // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. // TODO: This omits argument count check - enable only at -O3 or similar. // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { @@ -662,8 +658,8 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["throwBindingError", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; - var args2 = [throwBindingError, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; if (isClassMethodFunc) { invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; @@ -708,10 +704,43 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp return invokerFunction; } -function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { +function requireFunction(signature, rawFunction) { + signature = readLatin1String(signature); + var fp; + // asm.js does not define FUNCTION_TABLE + if (typeof FUNCTION_TABLE === "undefined") { + // asm.js does not give direct access to the function tables, + // and thus we must go through the dynCall interface which allows + // calling into a signature's function table by pointer value. + // + // https://github.com/dherman/asm.js/issues/83 + // + // This has three main penalties: + // - dynCall is another function call in the path from JavaScript to C++. + // - JITs may not predict through the function table indirection at runtime. + // - Function.prototype.bind generally benchmarks poorly relative to + // function objects, but using 'arguments' would confound JITs and + // possibly allocate. + var dc = asm['dynCall_' + signature]; + if (dc === undefined) { + throwBindingError("No dynCall invoker for signature: " + signature); + } + fp = asm['dynCall_' + signature].bind(undefined, rawFunction); + } else { + fp = FUNCTION_TABLE[rawFunction]; + } + + if (typeof fp !== "function") { + throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); + } + return fp; +} + +function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + + rawInvoker = requireFunction(signature, rawInvoker); exposePublicSymbol(name, function() { throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); @@ -726,11 +755,11 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, var tupleRegistrations = {}; -function __embind_register_value_array(rawType, name, rawConstructor, rawDestructor) { +function __embind_register_value_array(rawType, name, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { tupleRegistrations[rawType] = { name: readLatin1String(name), - rawConstructor: FUNCTION_TABLE[rawConstructor], - rawDestructor: FUNCTION_TABLE[rawDestructor], + rawConstructor: requireFunction(constructorSignature, rawConstructor), + rawDestructor: requireFunction(destructorSignature, rawDestructor), elements: [], }; } @@ -738,18 +767,20 @@ function __embind_register_value_array(rawType, name, rawConstructor, rawDestruc function __embind_register_value_array_element( rawTupleType, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { tupleRegistrations[rawTupleType].elements.push({ getterReturnType: getterReturnType, - getter: FUNCTION_TABLE[getter], + getter: requireFunction(getterSignature, getter), getterContext: getterContext, setterArgumentType: setterArgumentType, - setter: FUNCTION_TABLE[setter], + setter: requireFunction(setterSignature, setter), setterContext: setterContext, }); } @@ -818,13 +849,15 @@ var structRegistrations = {}; function __embind_register_value_object( rawType, name, + constructorSignature, rawConstructor, + destructorSignature, rawDestructor ) { structRegistrations[rawType] = { name: readLatin1String(name), - rawConstructor: FUNCTION_TABLE[rawConstructor], - rawDestructor: FUNCTION_TABLE[rawDestructor], + rawConstructor: requireFunction(constructorSignature, rawConstructor), + rawDestructor: requireFunction(destructorSignature, rawDestructor), fields: [], }; } @@ -833,19 +866,21 @@ function __embind_register_value_object_field( structType, fieldName, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { structRegistrations[structType].fields.push({ fieldName: readLatin1String(fieldName), getterReturnType: getterReturnType, - getter: FUNCTION_TABLE[getter], + getter: requireFunction(getterSignature, getter), getterContext: getterContext, setterArgumentType: setterArgumentType, - setter: FUNCTION_TABLE[setter], + setter: requireFunction(setterSignature, setter), setterContext: setterContext, }); } @@ -1324,17 +1359,25 @@ function __embind_register_class( rawPointerType, rawConstPointerType, baseClassRawType, + getActualTypeSignature, getActualType, + upcastSignature, upcast, + downcastSignature, downcast, name, + destructorSignature, rawDestructor ) { name = readLatin1String(name); - rawDestructor = FUNCTION_TABLE[rawDestructor]; - getActualType = FUNCTION_TABLE[getActualType]; - upcast = FUNCTION_TABLE[upcast]; - downcast = FUNCTION_TABLE[downcast]; + getActualType = requireFunction(getActualTypeSignature, getActualType); + if (upcast) { + upcast = requireFunction(upcastSignature, upcast); + } + if (downcast) { + downcast = requireFunction(downcastSignature, downcast); + } + rawDestructor = requireFunction(destructorSignature, rawDestructor); var legalFunctionName = makeLegalFunctionName(name); exposePublicSymbol(legalFunctionName, function() { @@ -1424,11 +1467,12 @@ function __embind_register_class_constructor( rawClassType, argCount, rawArgTypesAddr, + invokerSignature, invoker, rawConstructor ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = FUNCTION_TABLE[invoker]; + invoker = requireFunction(invokerSignature, invoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1513,12 +1557,13 @@ function __embind_register_class_function( methodName, argCount, rawArgTypesAddr, // [ReturnType, ThisType, Args...] + invokerSignature, rawInvoker, context ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + rawInvoker = requireFunction(invokerSignature, rawInvoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1564,12 +1609,13 @@ function __embind_register_class_class_function( methodName, argCount, rawArgTypesAddr, + invokerSignature, rawInvoker, fn ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + rawInvoker = requireFunction(invokerSignature, rawInvoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; var humanName = classType.name + '.' + methodName; @@ -1609,14 +1655,16 @@ function __embind_register_class_property( classType, fieldName, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { fieldName = readLatin1String(fieldName); - getter = FUNCTION_TABLE[getter]; + getter = requireFunction(getterSignature, getter); whenDependentTypesAreResolved([], [classType], function(classType) { classType = classType[0]; @@ -1654,7 +1702,7 @@ function __embind_register_class_property( }; if (setter) { - setter = FUNCTION_TABLE[setter]; + setter = requireFunction(setterSignature, setter); var setterArgumentType = types[1]; desc.set = function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); @@ -1689,16 +1737,20 @@ function __embind_register_smart_ptr( rawPointeeType, name, sharingPolicy, + getPointeeSignature, rawGetPointee, + constructorSignature, rawConstructor, + shareSignature, rawShare, + destructorSignature, rawDestructor ) { name = readLatin1String(name); - rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawShare = FUNCTION_TABLE[rawShare]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; + rawGetPointee = requireFunction(getPointeeSignature, rawGetPointee); + rawConstructor = requireFunction(constructorSignature, rawConstructor); + rawShare = requireFunction(shareSignature, rawShare); + rawDestructor = requireFunction(destructorSignature, rawDestructor); whenDependentTypesAreResolved([rawType], [rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 0699715c..699e834b 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -20,6 +20,8 @@ namespace emscripten { namespace internal { typedef long GenericEnumValue; + typedef void (*GenericFunction)(); + // Implemented in JavaScript. Don't call these directly. extern "C" { void _embind_fatal_error( @@ -70,21 +72,26 @@ namespace emscripten { const char* name, unsigned argCount, TYPEID argTypes[], + const char* signature, GenericFunction invoker, GenericFunction function); void _embind_register_value_array( TYPEID tupleType, const char* name, + const char* constructorSignature, GenericFunction constructor, + const char* destructorSignature, GenericFunction destructor); void _embind_register_value_array_element( TYPEID tupleType, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); @@ -93,46 +100,45 @@ namespace emscripten { void _embind_register_value_object( TYPEID structType, const char* fieldName, + const char* constructorSignature, GenericFunction constructor, + const char* destructorSignature, GenericFunction destructor); void _embind_register_value_object_field( TYPEID structType, const char* fieldName, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); void _embind_finalize_value_object(TYPEID structType); - void _embind_register_smart_ptr( - TYPEID pointerType, - TYPEID pointeeType, - const char* pointerName, - sharing_policy sharingPolicy, - GenericFunction getPointee, - GenericFunction constructor, - GenericFunction share, - GenericFunction destructor); - void _embind_register_class( TYPEID classType, TYPEID pointerType, TYPEID constPointerType, TYPEID baseClassType, + const char* getActualTypeSignature, GenericFunction getActualType, + const char* upcastSignature, GenericFunction upcast, + const char* downcastSignature, GenericFunction downcast, const char* className, + const char* destructorSignature, GenericFunction destructor); void _embind_register_class_constructor( TYPEID classType, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, GenericFunction constructor); @@ -141,6 +147,7 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, void* context); @@ -148,9 +155,11 @@ namespace emscripten { TYPEID classType, const char* fieldName, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); @@ -159,6 +168,7 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, GenericFunction method); @@ -168,17 +178,25 @@ namespace emscripten { size_t size, bool isSigned); + void _embind_register_smart_ptr( + TYPEID pointerType, + TYPEID pointeeType, + const char* pointerName, + sharing_policy sharingPolicy, + const char* getPointeeSignature, + GenericFunction getPointee, + const char* constructorSignature, + GenericFunction constructor, + const char* shareSignature, + GenericFunction share, + const char* destructorSignature, + GenericFunction destructor); + void _embind_register_enum_value( TYPEID enumType, const char* valueName, GenericEnumValue value); - void _embind_register_interface( - TYPEID interfaceType, - const char* name, - GenericFunction constructor, - GenericFunction destructor); - void _embind_register_constant( const char* name, TYPEID constantType, @@ -291,6 +309,63 @@ namespace emscripten { } //////////////////////////////////////////////////////////////////////////////// + // SignatureCode, SignatureString + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template<typename T> + struct SignatureCode { + static constexpr char get() { + return 'i'; + } + }; + + template<> + struct SignatureCode<void> { + static constexpr char get() { + return 'v'; + } + }; + + template<> + struct SignatureCode<float> { + static constexpr char get() { + return 'd'; + } + }; + + template<> + struct SignatureCode<double> { + static constexpr char get() { + return 'd'; + } + }; + + template<typename... T> + struct SignatureString; + + template<> + struct SignatureString<> { + char c = 0; + }; + + template<typename First, typename... Rest> + struct SignatureString<First, Rest...> { + constexpr SignatureString() + : c(SignatureCode<First>::get()) + {} + char c; + SignatureString<Rest...> rest; + }; + + template<typename Return, typename... Args> + const char* getSignature(Return (*)(Args...)) { + static constexpr SignatureString<Return, Args...> sig; + return &sig.c; + } + } + + //////////////////////////////////////////////////////////////////////////////// // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// @@ -302,11 +377,13 @@ namespace emscripten { void function(const char* name, ReturnType (*fn)(Args...), Policies...) { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, Args...> args; + auto invoker = &Invoker<ReturnType, Args...>::invoke; _embind_register_function( name, args.count, args.types, - reinterpret_cast<GenericFunction>(&Invoker<ReturnType, Args...>::invoke), + getSignature(invoker), + reinterpret_cast<GenericFunction>(invoker), reinterpret_cast<GenericFunction>(fn)); } @@ -542,11 +619,16 @@ namespace emscripten { value_array(const char* name) { using namespace internal; + + auto constructor = &raw_constructor<ClassType>; + auto destructor = &raw_destructor<ClassType>; _embind_register_value_array( TypeID<ClassType>::get(), name, - reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), - reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); + getSignature(constructor), + reinterpret_cast<GenericFunction>(constructor), + getSignature(destructor), + reinterpret_cast<GenericFunction>(destructor)); } ~value_array() { @@ -557,17 +639,21 @@ namespace emscripten { template<typename InstanceType, typename ElementType> value_array& element(ElementType InstanceType::*field) { using namespace internal; + + auto getter = &MemberAccess<InstanceType, ElementType> + ::template getWire<ClassType>; + auto setter = &MemberAccess<InstanceType, ElementType> + ::template setWire<ClassType>; + _embind_register_value_array_element( TypeID<ClassType>::get(), TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>( - &MemberAccess<InstanceType, ElementType> - ::template getWire<ClassType>), + getSignature(getter), + reinterpret_cast<GenericFunction>(getter), getContext(field), TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>( - &MemberAccess<InstanceType, ElementType> - ::template setWire<ClassType>), + getSignature(setter), + reinterpret_cast<GenericFunction>(setter), getContext(field)); return *this; } @@ -577,13 +663,19 @@ namespace emscripten { using namespace internal; typedef GetterPolicy<Getter> GP; typedef SetterPolicy<Setter> SP; + + auto g = &GP::template get<ClassType>; + auto s = &SP::template set<ClassType>; + _embind_register_value_array_element( TypeID<ClassType>::get(), TypeID<typename GP::ReturnType>::get(), - reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + getSignature(g), + reinterpret_cast<GenericFunction>(g), GP::getContext(getter), TypeID<typename SP::ArgumentType>::get(), - reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + getSignature(s), + reinterpret_cast<GenericFunction>(s), SP::getContext(setter)); return *this; } @@ -593,13 +685,18 @@ namespace emscripten { using namespace internal; ClassType* null = 0; typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + auto getter = &internal::get_by_index<ClassType, ElementType>; + auto setter = &internal::set_by_index<ClassType, ElementType>; + _embind_register_value_array_element( TypeID<ClassType>::get(), TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + getSignature(getter), + reinterpret_cast<GenericFunction>(getter), reinterpret_cast<void*>(Index), TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + getSignature(setter), + reinterpret_cast<GenericFunction>(setter), reinterpret_cast<void*>(Index)); return *this; } @@ -616,11 +713,17 @@ namespace emscripten { value_object(const char* name) { using namespace internal; + + auto ctor = &raw_constructor<ClassType>; + auto dtor = &raw_destructor<ClassType>; + _embind_register_value_object( TypeID<ClassType>::get(), name, - reinterpret_cast<GenericFunction>(&raw_constructor<ClassType>), - reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); + getSignature(ctor), + reinterpret_cast<GenericFunction>(ctor), + getSignature(dtor), + reinterpret_cast<GenericFunction>(dtor)); } ~value_object() { @@ -630,18 +733,22 @@ namespace emscripten { template<typename InstanceType, typename FieldType> value_object& field(const char* fieldName, FieldType InstanceType::*field) { using namespace internal; + + auto getter = &MemberAccess<InstanceType, FieldType> + ::template getWire<ClassType>; + auto setter = &MemberAccess<InstanceType, FieldType> + ::template setWire<ClassType>; + _embind_register_value_object_field( TypeID<ClassType>::get(), fieldName, TypeID<FieldType>::get(), - reinterpret_cast<GenericFunction>( - &MemberAccess<InstanceType, FieldType> - ::template getWire<ClassType>), + getSignature(getter), + reinterpret_cast<GenericFunction>(getter), getContext(field), TypeID<FieldType>::get(), - reinterpret_cast<GenericFunction>( - &MemberAccess<InstanceType, FieldType> - ::template setWire<ClassType>), + getSignature(setter), + reinterpret_cast<GenericFunction>(setter), getContext(field)); return *this; } @@ -655,14 +762,20 @@ namespace emscripten { using namespace internal; typedef GetterPolicy<Getter> GP; typedef SetterPolicy<Setter> SP; + + auto g = &GP::template get<ClassType>; + auto s = &SP::template set<ClassType>; + _embind_register_value_object_field( TypeID<ClassType>::get(), fieldName, TypeID<typename GP::ReturnType>::get(), - reinterpret_cast<GenericFunction>(&GP::template get<ClassType>), + getSignature(g), + reinterpret_cast<GenericFunction>(g), GP::getContext(getter), TypeID<typename SP::ArgumentType>::get(), - reinterpret_cast<GenericFunction>(&SP::template set<ClassType>), + getSignature(s), + reinterpret_cast<GenericFunction>(s), SP::getContext(setter)); return *this; } @@ -672,14 +785,20 @@ namespace emscripten { using namespace internal; ClassType* null = 0; typedef typename std::remove_reference<decltype((*null)[Index])>::type ElementType; + + auto getter = &internal::get_by_index<ClassType, ElementType>; + auto setter = &internal::set_by_index<ClassType, ElementType>; + _embind_register_value_object_field( TypeID<ClassType>::get(), fieldName, TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>(&internal::get_by_index<ClassType, ElementType>), + getSignature(getter), + reinterpret_cast<GenericFunction>(getter), reinterpret_cast<void*>(Index), TypeID<ElementType>::get(), - reinterpret_cast<GenericFunction>(&internal::set_by_index<ClassType, ElementType>), + getSignature(setter), + reinterpret_cast<GenericFunction>(setter), reinterpret_cast<void*>(Index)); return *this; } @@ -832,13 +951,19 @@ namespace emscripten { } template<typename ClassType> - static internal::GenericFunction getUpcaster() { - return reinterpret_cast<internal::GenericFunction>(&convertPointer<ClassType, BaseClass>); + using Upcaster = BaseClass* (*)(ClassType*); + + template<typename ClassType> + using Downcaster = ClassType* (*)(BaseClass*); + + template<typename ClassType> + static Upcaster<ClassType> getUpcaster() { + return &convertPointer<ClassType, BaseClass>; } template<typename ClassType> - static internal::GenericFunction getDowncaster() { - return reinterpret_cast<internal::GenericFunction>(&convertPointer<BaseClass, ClassType>); + static Downcaster<ClassType> getDowncaster() { + return &convertPointer<BaseClass, ClassType>; } template<typename From, typename To> @@ -877,16 +1002,25 @@ namespace emscripten { BaseSpecifier::template verify<ClassType>(); + auto _getActualType = &getActualType<ClassType>; + auto upcast = BaseSpecifier::template getUpcaster<ClassType>(); + auto downcast = BaseSpecifier::template getDowncaster<ClassType>(); + auto destructor = &raw_destructor<ClassType>; + _embind_register_class( TypeID<ClassType>::get(), TypeID<AllowedRawPointer<ClassType>>::get(), TypeID<AllowedRawPointer<const ClassType>>::get(), BaseSpecifier::get(), - reinterpret_cast<GenericFunction>(&getActualType<ClassType>), - BaseSpecifier::template getUpcaster<ClassType>(), - BaseSpecifier::template getDowncaster<ClassType>(), + getSignature(_getActualType), + reinterpret_cast<GenericFunction>(_getActualType), + getSignature(upcast), + reinterpret_cast<GenericFunction>(upcast), + getSignature(downcast), + reinterpret_cast<GenericFunction>(downcast), name, - reinterpret_cast<GenericFunction>(&raw_destructor<ClassType>)); + getSignature(destructor), + reinterpret_cast<GenericFunction>(destructor)); } template<typename PointerType> @@ -898,15 +1032,24 @@ namespace emscripten { static_assert(std::is_same<ClassType, typename std::remove_cv<PointeeType>::type>::value, "smart pointer must point to this class"); + auto get = &PointerTrait::get; + auto construct_null = &PointerTrait::construct_null; + auto share = &PointerTrait::share; + auto destructor = &raw_destructor<PointerType>; + _embind_register_smart_ptr( TypeID<PointerType>::get(), TypeID<PointeeType>::get(), name, PointerTrait::get_sharing_policy(), - reinterpret_cast<GenericFunction>(&PointerTrait::get), - reinterpret_cast<GenericFunction>(&PointerTrait::construct_null), - reinterpret_cast<GenericFunction>(&PointerTrait::share), - reinterpret_cast<GenericFunction>(&raw_destructor<PointerType>)); + getSignature(get), + reinterpret_cast<GenericFunction>(get), + getSignature(construct_null), + reinterpret_cast<GenericFunction>(construct_null), + getSignature(share), + reinterpret_cast<GenericFunction>(share), + getSignature(destructor), + reinterpret_cast<GenericFunction>(destructor)); return *this; }; @@ -923,11 +1066,13 @@ namespace emscripten { // TODO: allows all raw pointers... policies need a rethink typename WithPolicies<allow_raw_pointers, Policies...>::template ArgTypeList<ReturnType, Args...> args; + auto invoke = &Invoker<ReturnType, Args...>::invoke; _embind_register_class_constructor( TypeID<ClassType>::get(), args.count, args.types, - reinterpret_cast<GenericFunction>(&Invoker<ReturnType, Args...>::invoke), + getSignature(invoke), + reinterpret_cast<GenericFunction>(invoke), reinterpret_cast<GenericFunction>(factory)); return *this; } @@ -939,11 +1084,13 @@ namespace emscripten { smart_ptr<SmartPtr>(smartPtrName); typename WithPolicies<Policies...>::template ArgTypeList<SmartPtr, Args...> args; + auto invoke = &Invoker<SmartPtr, Args...>::invoke; _embind_register_class_constructor( TypeID<ClassType>::get(), args.count, args.types, - reinterpret_cast<GenericFunction>(&Invoker<SmartPtr, Args...>::invoke), + getSignature(invoke), + reinterpret_cast<GenericFunction>(invoke), reinterpret_cast<GenericFunction>(factory)); return *this; } @@ -966,13 +1113,16 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) const { using namespace internal; + auto invoker = &MethodInvoker<decltype(memberFunction), ReturnType, ClassType*, Args...>::invoke; + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<ClassType>, Args...> args; _embind_register_class_function( TypeID<ClassType>::get(), methodName, args.count, args.types, - reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, ClassType*, Args...>::invoke), + getSignature(invoker), + reinterpret_cast<GenericFunction>(invoker), getContext(memberFunction)); return *this; } @@ -981,13 +1131,16 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) const { using namespace internal; + auto invoker = &MethodInvoker<decltype(memberFunction), ReturnType, const ClassType*, Args...>::invoke; + typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, AllowedRawPointer<const ClassType>, Args...> args; _embind_register_class_function( TypeID<ClassType>::get(), methodName, args.count, args.types, - reinterpret_cast<GenericFunction>(&MethodInvoker<decltype(memberFunction), ReturnType, const ClassType*, Args...>::invoke), + getSignature(invoker), + reinterpret_cast<GenericFunction>(invoker), getContext(memberFunction)); return *this; } @@ -997,12 +1150,14 @@ namespace emscripten { using namespace internal; typename WithPolicies<Policies...>::template ArgTypeList<ReturnType, ThisType, Args...> args; + auto invoke = &FunctionInvoker<decltype(function) |