aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChad Austin <caustin@gmail.com>2014-03-24 00:54:18 -0700
committerChad Austin <chad@chadaustin.me>2014-03-28 23:56:41 -0700
commitfa3e4f460a86ee2e0212fe2471690f67b9b4280c (patch)
tree8f29ee37885f8249bd9bea84bf5dadc5acf99048
parentbcb2da768ab5b559b1603b28e3f7b1a3e1b0b6fc (diff)
Make val::call<> compatible with asm.js
-rw-r--r--src/embind/embind.js11
-rw-r--r--src/embind/emval.js49
-rw-r--r--system/include/emscripten/val.h49
-rw-r--r--tests/embind/embind.test.js13
-rw-r--r--tests/embind/embind_test.cpp6
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);
}