replace the Function.prototype.bind in embind asm.js with a bind-time-generated trampoline. This results in a 500% reduction in call overhead in Chrome. (Very little change in Firefox)

This commit is contained in:
Chad Austin 2014-11-14 21:41:53 -08:00
Родитель 8e82818224
Коммит a563da7adc
1 изменённых файлов: 16 добавлений и 4 удалений

Просмотреть файл

@ -901,6 +901,21 @@ var LibraryEmbind = {
$requireFunction__deps: ['$readLatin1String', '$throwBindingError'],
$requireFunction: function(signature, rawFunction) {
signature = readLatin1String(signature);
function makeDynCaller(dynCall) {
var args = [];
for (var i = 1; i < signature.length; ++i) {
args.push('a' + i);
}
var name = 'dynCall_' + signature + '_' + rawFunction;
var body = 'return function ' + name + '(' + args.join(', ') + ') {\n';
body += ' return dynCall(rawFunction' + (args.length ? ', ' : '') + args.join(', ') + ');\n';
body += '};\n';
return (new Function('dynCall', 'rawFunction', body))(dynCall, rawFunction);
}
var fp;
// asm.js does not define FUNCTION_TABLE
if (typeof FUNCTION_TABLE === "undefined") {
@ -913,9 +928,6 @@ var LibraryEmbind = {
// This has three main penalties:
// - dynCall is another function call in the path from JavaScript to C++.
// - JITs may not predict through the function table indirection at runtime.
// - Function.prototype.bind generally benchmarks poorly relative to
// function objects, but using 'arguments' would confound JITs and
// possibly allocate.
var dc = asm['dynCall_' + signature];
if (dc === undefined) {
// We will always enter this branch if the signature
@ -927,7 +939,7 @@ var LibraryEmbind = {
throwBindingError("No dynCall invoker for signature: " + signature);
}
}
fp = dc.bind(undefined, rawFunction);
fp = makeDynCaller(dc);
} else {
fp = FUNCTION_TABLE[rawFunction];
}