diff options
author | Jukka Jylänki <jujjyl@gmail.com> | 2013-04-15 21:13:42 +0300 |
---|---|---|
committer | Jukka Jylänki <jujjyl@gmail.com> | 2013-04-18 20:08:29 +0300 |
commit | a0406a1cb9d0de51c923fca1c1e2e637dd3bd57a (patch) | |
tree | 0e974c0ba22f8ad9253617f6550397e8e6b0eee1 | |
parent | 51c2826d68883d2324c728558aa10a8ffc299d1b (diff) |
Embind: Merge makeInvoker and class member function invoker generator functions into one to remove code duplication.
-rwxr-xr-x | src/embind/embind.js | 187 |
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 { |