diff options
author | Chad Austin <caustin@gmail.com> | 2014-03-24 00:54:18 -0700 |
---|---|---|
committer | Chad Austin <chad@chadaustin.me> | 2014-03-28 23:56:41 -0700 |
commit | fa3e4f460a86ee2e0212fe2471690f67b9b4280c (patch) | |
tree | 8f29ee37885f8249bd9bea84bf5dadc5acf99048 | |
parent | bcb2da768ab5b559b1603b28e3f7b1a3e1b0b6fc (diff) |
Make val::call<> compatible with asm.js
-rw-r--r-- | src/embind/embind.js | 11 | ||||
-rw-r--r-- | src/embind/emval.js | 49 | ||||
-rw-r--r-- | system/include/emscripten/val.h | 49 | ||||
-rw-r--r-- | tests/embind/embind.test.js | 13 | ||||
-rw-r--r-- | tests/embind/embind_test.cpp | 6 |
5 files changed, 92 insertions, 36 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js index 4ef8646f..1fb9403f 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -164,6 +164,10 @@ var typeDependencies = {}; var registeredPointers = {}; function registerType(rawType, registeredInstance) { + if (!('varArgAdvance' in registeredInstance)) { + throw new TypeError('registerType registeredInstance requires varArgAdvance'); + } + var name = registeredInstance.name; if (!rawType) { throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); @@ -268,6 +272,7 @@ function __embind_register_void(rawType, name) { name = readLatin1String(name); registerType(rawType, { name: name, + 'varArgAdvance': 0, 'fromWireType': function() { return undefined; }, @@ -432,8 +437,10 @@ function __embind_register_float(rawType, name, size) { }, 'varArgAdvance': 8, 'readValueFromPointer': function(pointer) { - var heap = (shift === 2) ? HEAPF32 : HEAPF64; - return this['fromWireType'](heap[pointer >> shift]); + // TODO: rename readValueFromPointer to + // readValueFromVarArg in clang/emscripten, it appears + // floats are passed in varargs via HEAPF64 + return this['fromWireType'](HEAPF64[pointer >> 3]); }, writeValueToPointer: function(value, pointer, _destructors) { var heap = (shift === 2) ? HEAPF32 : HEAPF64; diff --git a/src/embind/emval.js b/src/embind/emval.js index 535b5d57..3dfe0f00 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -228,40 +228,55 @@ function allocateDestructors(destructorsRef) { return destructors; } +// Leave id 0 undefined. It's not a big deal, but might be confusing +// to have null be a valid method caller. +var methodCallers = [undefined]; + +function addMethodCaller(caller) { + var id = methodCallers.length; + methodCallers.push(caller); + return id; +} + function __emval_get_method_caller(argCount, argTypes) { var types = lookupTypes(argCount, argTypes); var retType = types[0]; var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; - var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "retType", "allocateDestructors"]; - var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, retType, allocateDestructors]; + var params = ["retType"]; + var args = [retType]; var argsList = ""; // 'arg0, arg1, arg2, ... , argN' - var argsListWired = ""; // 'arg0Wired, ..., argNWired' for (var i = 0; i < argCount - 1; ++i) { argsList += (i !== 0 ? ", " : "") + "arg" + i; - argsListWired += ", arg" + i + "Wired"; - args1.push("argType" + i); - args2.push(types[1 + i]); + params.push("argType" + i); + args.push(types[1 + i]); } - var invokerFnBody = - "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name, destructorsRef" + argsListWired + ") {\n" + - " var handle = requireHandle(handle);\n" + - " name = getStringOrSymbol(name);\n"; + var functionBody = + "return function (handle, name, destructors, args) {\n"; for (var i = 0; i < argCount - 1; ++i) { - invokerFnBody += " var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n"; + functionBody += + " var arg" + i + " = argType" + i + ".readValueFromPointer(args);\n" + + " args += argType" + i + ".varArgAdvance;\n"; } - invokerFnBody += + functionBody += " var rv = handle[name](" + argsList + ");\n" + - " return retType.toWireType(allocateDestructors(destructorsRef), rv);\n" + - "}));\n"; + " return retType.toWireType(destructors, rv);\n" + + "};\n"; - args1.push(invokerFnBody); - var invokerFunction = new_(Function, args1).apply(null, args2); - return invokerFunction; + params.push(functionBody); + var invokerFunction = new_(Function, params).apply(null, args); + return addMethodCaller(createNamedFunction(signatureName, invokerFunction)); +} + +function __emval_call_method(caller, handle, methodName, destructorsRef, args) { + caller = methodCallers[caller]; + handle = requireHandle(handle); + methodName = getStringOrSymbol(methodName); + return caller(handle, methodName, allocateDestructors(destructorsRef), args); } function __emval_has_function(handle, name) { diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 78805f5a..5b69e0ff 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -12,6 +12,8 @@ namespace emscripten { typedef struct _EM_VAL* EM_VAL; typedef struct _EM_DESTRUCTORS* EM_DESTRUCTORS; + typedef struct _EM_METHOD_CALLER* EM_METHOD_CALLER; + typedef double EM_GENERIC_WIRE_TYPE; void _emval_incref(EM_VAL value); void _emval_decref(EM_VAL value); @@ -35,7 +37,7 @@ namespace emscripten { EM_VAL _emval_get_module_property(const char* name); EM_VAL _emval_get_property(EM_VAL object, EM_VAL key); void _emval_set_property(EM_VAL object, EM_VAL key, EM_VAL value); - double _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* destructors); + EM_GENERIC_WIRE_TYPE _emval_as(EM_VAL value, TYPEID returnType, EM_DESTRUCTORS* destructors); // TODO: make compatible with asm.js EM_VAL _emval_call( @@ -44,17 +46,24 @@ namespace emscripten { internal::TYPEID argTypes[] /*, ... */); - // DO NOT call this more than once per signature. It will leak function pointer offsets! - GenericFunction _emval_get_method_caller( + // DO NOT call this more than once per signature. It will + // leak generated function objects! + EM_METHOD_CALLER _emval_get_method_caller( unsigned argCount, // including return value internal::TYPEID argTypes[]); + EM_GENERIC_WIRE_TYPE _emval_call_method( + EM_METHOD_CALLER caller, + EM_VAL handle, + const char* methodName, + EM_DESTRUCTORS* destructors, + ...); bool _emval_has_function( EM_VAL value, const char* methodName); } template<const char* address> - struct symbol_registrar { + struct symbol_registrar { symbol_registrar() { internal::_emval_register_symbol(address); } @@ -62,19 +71,21 @@ namespace emscripten { template<typename ReturnType, typename... Args> struct Signature { + /* typedef typename BindingType<ReturnType>::WireType (*MethodCaller)( EM_VAL value, const char* methodName, EM_DESTRUCTORS* destructors, typename BindingType<Args>::WireType...); + */ - static MethodCaller get_method_caller() { - static MethodCaller fp = reinterpret_cast<MethodCaller>(init_method_caller()); - return fp; + static EM_METHOD_CALLER get_method_caller() { + static EM_METHOD_CALLER mc = init_method_caller(); + return mc; } private: - static GenericFunction init_method_caller() { + static EM_METHOD_CALLER init_method_caller() { WithPolicies<>::ArgTypeList<ReturnType, Args...> args; return _emval_get_method_caller(args.count, args.types); } @@ -110,9 +121,11 @@ namespace emscripten { } }; - template<typename WireType> - WireType fromGenericWireType(double wt) { - return GenericWireTypeConverter<WireType>::from(wt); + template<typename T> + T fromGenericWireType(double g) { + typedef typename BindingType<T>::WireType WireType; + WireType wt = GenericWireTypeConverter<WireType>::from(g); + return BindingType<T>::fromWireType(wt); } template<typename ReturnType, typename... Args> @@ -121,13 +134,14 @@ namespace emscripten { auto caller = Signature<ReturnType, Args...>::get_method_caller(); EM_DESTRUCTORS destructors; - auto wireType = caller( + EM_GENERIC_WIRE_TYPE result = _emval_call_method( + caller, handle, methodName, &destructors, toWireType(std::forward<Args>(args))...); DestructorsRunner rd(destructors); - return BindingType<ReturnType>::fromWireType(wireType); + return fromGenericWireType<ReturnType>(result); } }; @@ -137,7 +151,8 @@ namespace emscripten { auto caller = Signature<void, Args...>::get_method_caller(); EM_DESTRUCTORS destructors; - caller( + _emval_call_method( + caller, handle, methodName, &destructors, @@ -307,12 +322,12 @@ namespace emscripten { typedef BindingType<T> BT; EM_DESTRUCTORS destructors; - auto result = fromGenericWireType<typename BindingType<T>::WireType>(_emval_as( + EM_GENERIC_WIRE_TYPE result = _emval_as( handle, TypeID<T>::get(), - &destructors)); + &destructors); DestructorsRunner dr(destructors); - return BT::fromWireType(result); + return fromGenericWireType<T>(result); } private: diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 4ac8fe52..e2160c33 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -1997,6 +1997,19 @@ module({ assert.equal(10, instance.view.byteLength); assert.equal("after", instance.after); }); + + test("ints_and_float", function() { + function factory(a, b, c) { + this.a = a; + this.b = b; + this.c = c; + } + + var instance = cm.construct_with_ints_and_float(factory); + assert.equal(65537, instance.a); + assert.equal(4.0, instance.b); + assert.equal(65538, instance.c); + }); }); }); diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 0b3f67e9..d299660a 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -2351,7 +2351,13 @@ val construct_with_memory_view(val factory) { std::string("after")); } +val construct_with_ints_and_float(val factory) { + static const char data[11] = "0123456789"; + return factory.new_(65537, 4.0f, 65538); +} + EMSCRIPTEN_BINDINGS(val_new_) { function("construct_with_6_arguments", &construct_with_6); function("construct_with_memory_view", &construct_with_memory_view); + function("construct_with_ints_and_float", &construct_with_ints_and_float); } |