aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Jylänki <jujjyl@gmail.com>2013-04-15 21:13:42 +0300
committerJukka Jylänki <jujjyl@gmail.com>2013-04-18 20:08:29 +0300
commita0406a1cb9d0de51c923fca1c1e2e637dd3bd57a (patch)
tree0e974c0ba22f8ad9253617f6550397e8e6b0eee1
parent51c2826d68883d2324c728558aa10a8ffc299d1b (diff)
Embind: Merge makeInvoker and class member function invoker generator functions into one to remove code duplication.
-rwxr-xr-xsrc/embind/embind.js187
1 files changed, 92 insertions, 95 deletions
diff --git a/src/embind/embind.js b/src/embind/embind.js
index 4cc111a3..0af19bb1 100755
--- a/src/embind/embind.js
+++ b/src/embind/embind.js
@@ -481,44 +481,107 @@ function new_(constructor, argumentList) {
return (r instanceof Object) ? r : obj;
};
-function makeInvoker(name, argCount, argTypes, invoker, fn) {
- if (!FUNCTION_TABLE[fn]) {
- throwBindingError('function '+name+' is not defined');
+// The path to interop from JS code to C++ code:
+// (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function)
+// craftInvokerFunction generates the JS invoker function for each function exposed to JS through embind.
+function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) {
+ // humanName: a human-readable string name for the function to be generated.
+ // argTypes: An array that contains the embind type objects for all types in the function signature.
+ // argTypes[0] is the type object for the function return value.
+ // argTypes[1] is the type object for function this object/class type, or null if not crafting an invoker for a class method.
+ // argTypes[2...] are the actual function parameters.
+ // classType: The embind type object for the class to be bound, or null if this is not a method of a class.
+ // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code.
+ // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling.
+ var argCount = argTypes.length;
+
+ if (argCount < 2) {
+ throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!");
+ }
+
+ var isClassMethodFunc = (argTypes[1] !== null && classType !== null);
+
+ if (!isClassMethodFunc && !FUNCTION_TABLE[cppTargetFunc]) {
+ throwBindingError('Global function '+humanName+' is not defined!');
}
- // Functions with signature "void function()" do not need an invoker that marshalls between wire types.
+ // 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 == 1 && argTypes[0].name == "void") {
+// if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) {
// return FUNCTION_TABLE[fn];
// }
- var invokerFnBody =
- "return function "+makeLegalFunctionName(name)+"() { " +
- "if (arguments.length !== "+(argCount - 1)+") {" +
- "throwBindingError('function "+name+" called with ' + arguments.length + ' arguments, expected "+(argCount - 1)+" args!');" +
- "}" +
- "var destructors = [];";
-
var argsList = "";
- var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType"];
- var args2 = [throwBindingError, invoker, fn, runDestructors, argTypes[0]];
+ for(i = 0; i < argCount-2; ++i) {
+ argsList += (i!=0?", ":"")+"arg"+i;
+ }
+
+ var invokerFnBody =
+ "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" +
+ "if (arguments.length !== "+(argCount - 2)+") {\n" +
+ "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" +
+ "}\n";// +
+ //"validateThis(this, classType, '"+humanName+"');\n";
+
+ // Determine if we need to use a dynamic stack to store the destructors for the function parameters.
+ // TODO: Remove this completely once all function invokers are being dynamically generated.
+ var needsDestructorStack = false;
+
+ for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here.
+ if (argTypes[i] !== null && argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack
+ needsDestructorStack = true;
+ break;
+ }
+ }
+
+ if (needsDestructorStack) {
+ invokerFnBody +=
+ "var destructors = [];\n";
+ }
- for(i = 0; i < argCount-1; ++i) {
- invokerFnBody += "var arg"+i+" = argType"+i+".toWireType(destructors, arguments["+i+"]);";
- argsList += ", arg"+i;
+ var dtorStack = needsDestructorStack ? "destructors" : "null";
+ var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"];
+ var args2 = [throwBindingError, validateThis, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]];
+
+ for(i = 0; i < argCount-2; ++i) {
+ invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n";
+ // argsList += ", arg"+i;
args1.push("argType"+i);
- args2.push(argTypes[i+1]);
+ args2.push(argTypes[i+2]);
+ }
+
+ if (isClassMethodFunc) {
+ invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"
+ argsList = "thisWired" + (argsList.length > 0 ? ", " : "") + argsList;
}
- invokerFnBody +=
- "var rv = invoker(fn"+argsList+");" +
- "runDestructors(destructors);" +
- "return retType.fromWireType(rv);" +
- "}";
+ var returns = (argTypes[0].name !== "void");
+
+ invokerFnBody +=
+ (returns?"var rv = ":"") + "invoker(fn"+(argsList.length>0?", ":"")+argsList+");\n";
+
+ if (needsDestructorStack) {
+ invokerFnBody += "runDestructors(destructors);\n";
+ } else {
+ for(i = isClassMethodFunc?1:2; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here. Also skip class type if not a method.
+ var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2)));
+ if (argTypes[i].destructorFunction !== null) {
+ invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n";
+ args1.push(paramName+"_dtor");
+ args2.push(argTypes[i].destructorFunction);
+ }
+ }
+ }
+
+ if (returns) {
+ invokerFnBody += "return retType.fromWireType(rv);\n";
+ }
+ invokerFnBody += "}\n";
args1.push(invokerFnBody);
- return new_(Function, args1).apply(null, args2);
+ var invokerFunction = new_(Function, args1).apply(null, args2);
+ return invokerFunction;
}
function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) {
@@ -531,7 +594,8 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker,
}, argCount - 1);
whenDependentTypesAreResolved([], argTypes, function(argTypes) {
- replacePublicSymbol(name, makeInvoker(name, argCount, argTypes, rawInvoker, fn), argCount - 1);
+ var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */);
+ replacePublicSymbol(name, craftInvokerFunction(name, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn), argCount - 1);
return [];
});
}
@@ -1266,75 +1330,7 @@ function __embind_register_class_function(
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
- var argsList = "";
- for(i = 0; i < argCount-2; ++i) {
- argsList += (i!=0?", ":"")+"arg"+i;
- }
-
- var invokerFnBody =
- "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" +
- "if (arguments.length !== "+(argCount - 2)+") {\n" +
- "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" +
- "}\n";// +
- //"validateThis(this, classType, '"+humanName+"');\n";
-
- // Determine if we need to use a dynamic stack to store the destructors for the function parameters.
- // TODO: Remove this completely once all function invokers are being dynamically generated.
- var needsDestructorStack = false;
-
- for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here.
- if (argTypes[i].destructorFunction === undefined) { // The type does not define a destructor function - must use dynamic stack
- needsDestructorStack = true;
- break;
- }
- }
-
- if (needsDestructorStack) {
- invokerFnBody +=
- "var destructors = [];\n";
- }
-
- var dtorStack = needsDestructorStack ? "destructors" : "null";
- var args1 = ["throwBindingError", "validateThis", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"];
- var args2 = [throwBindingError, validateThis, classType, rawInvoker, context, runDestructors, argTypes[0], argTypes[1]];
-
- for(i = 0; i < argCount-2; ++i) {
- invokerFnBody += "var arg"+i+" = argType"+i+".toWireType("+dtorStack+", arg"+i+"); // "+argTypes[i+2].name+"\n";
- argsList += ", arg"+i;
- args1.push("argType"+i);
- args2.push(argTypes[i+2]);
- }
-
- invokerFnBody +=
- "var thisWired = classParam.toWireType("+dtorStack+", this);\n"
-
- var returns = (argTypes[0].name !== "void");
-
- invokerFnBody +=
- (returns?"var rv = ":"") + "invoker(fn, thisWired"+(argCount-2>0?", ":"")+argsList+");\n";
-
- if (needsDestructorStack) {
- invokerFnBody += "runDestructors(destructors);\n";
- } else {
- for(i = 1; i < argTypes.length; ++i) { // Skip return value at index 0 - it's not deleted here.
- var paramName = (i == 1 ? "thisWired" : ("argType"+(i-2)));
- if (argTypes[i].destructorFunction !== null) {
- invokerFnBody += paramName+"_dtor("+paramName+"); // "+argTypes[i].name+"\n";
- args1.push(paramName+"_dtor");
- args2.push(argTypes[i].destructorFunction);
- }
- }
- }
-
- if (returns) {
- invokerFnBody += "return retType.fromWireType(rv);\n";
- }
- invokerFnBody += "}\n";
-
- args1.push(invokerFnBody);
-
- var memberFunction = new_(Function, args1).apply(null, args2);
- //Module.print(memberFunction);
+ var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context);
// Replace the initial unbound-handler-stub function with the appropriate member function, now that all types
// are resolved. If multiple overloads are registered for this function, the function goes into an overload table.
@@ -1383,7 +1379,8 @@ function __embind_register_class_class_function(
whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) {
// Replace the initial unbound-types-handler stub with the proper function. If multiple overloads are registered,
// the function handlers go into an overload table.
- var func = makeInvoker(humanName, argCount, argTypes, rawInvoker, fn);
+ var invokerArgsArray = [argTypes[0] /* return value */, null /* no class 'this'*/].concat(argTypes.slice(1) /* actual params */);
+ var func = craftInvokerFunction(humanName, invokerArgsArray, null /* no class 'this'*/, rawInvoker, fn);
if (undefined === proto[methodName].overloadTable) {
proto[methodName] = func;
} else {