aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Jylänki <jujjyl@gmail.com>2013-04-11 14:08:46 +0300
committerJukka Jylänki <jujjyl@gmail.com>2013-04-18 20:08:21 +0300
commit9a310fb5b6043e93bc37ebb894b8487fc9fd7ef6 (patch)
treefc6994953de0fb05501712406e7b5490a41e63fb
parent75881fce897a3c5849c139866fe46d39d6b05bcd (diff)
Optimize embind makeInvoker to not call function.apply or do for() loops. Instead, manually craft invoker functions for each function.
-rwxr-xr-xsrc/embind/embind.js71
1 files changed, 56 insertions, 15 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 753d40a4..00d56bc8 100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -447,25 +447,66 @@ function runDestructors(destructors) {
}
}
+// Function implementation of operator new, per
+// http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
+// 13.2.2
+// ES3
+function new_(constructor, argumentList) {
+ if (!(constructor instanceof Function)) {
+ throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function");
+ }
+
+ /*
+ * Previously, the following line was just:
+
+ function dummy() {};
+
+ * Unfortunately, Chrome was preserving 'dummy' as the object's name, even though at creation, the 'dummy' has the
+ * correct constructor name. Thus, objects created with IMVU.new would show up in the debugger as 'dummy', which
+ * isn't very helpful. Using IMVU.createNamedFunction addresses the issue. Doublely-unfortunately, there's no way
+ * to write a test for this behavior. -NRD 2013.02.22
+ */
+ var dummy = createNamedFunction(constructor.name, function(){});
+ dummy.prototype = constructor.prototype;
+ var obj = new dummy;
+
+ var r = constructor.apply(obj, argumentList);
+ return (r instanceof Object) ? r : obj;
+};
+
function makeInvoker(name, argCount, argTypes, invoker, fn) {
if (!FUNCTION_TABLE[fn]) {
throwBindingError('function '+name+' is not defined');
}
- return createNamedFunction(makeLegalFunctionName(name), function() {
- if (arguments.length !== argCount - 1) {
- throwBindingError('function ' + name + ' called with ' + arguments.length + ' arguments, expected ' + (argCount - 1));
- }
- var destructors = [];
- var args = new Array(argCount);
- args[0] = fn;
- for (var i = 1; i < argCount; ++i) {
- args[i] = argTypes[i].toWireType(destructors, arguments[i - 1]);
- }
- var rv = invoker.apply(null, args);
- rv = argTypes[0].fromWireType(rv);
- runDestructors(destructors);
- return rv;
- });
+ // Functions with signature "void function()" do not need an invoker that marshalls between wire types.
+ if (argCount == 1 && argTypes[0].name == "void") {
+ return FUNCTION_TABLE[fn];
+ }
+
+ var invokerFnBody =
+ "return function "+makeLegalFunctionName(name)+"() { " +
+ "var destructors = [];";
+
+ var argsList = "";
+ var args1 = ["invoker", "fn", "runDestructors", "retType" ];
+ var args2 = [invoker, fn, runDestructors, argTypes[0] ];
+
+ for(i = 0; i < argCount-1; ++i) {
+ invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);";
+ argsList += ", arg"+i;
+ args1.push("argType"+i);
+ args2.push(argTypes[i+1]);
+ }
+
+ invokerFnBody +=
+ "var rv = invoker(fn"+argsList+");" +
+ "runDestructors(destructors);" +
+ "return retType.fromWireType(rv);" +
+ "}";
+
+ args1.push(invokerFnBody);
+
+ return new_(Function, args1).apply(null, args2);
}
function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) {