If asm.js passes a function pointer (as a numeric index into a function table) to JavaScript, JavaScript currently has no way to look up the actual underlying function object. This is a severe penalty for Embind, which relies on the ability to map numeric function pointers to JavaScript function objects.
At the end of this post, see benchmark results with (oldcomp, non-asm.js) and without this functionality. You can see that the old Emscripten compiler without asm.js generates substantially faster calls through Embind.
Without function object lookup, Embind instead must go through an Emscripten-generated dynCall function, which adds some costly indirection: https://github.com/kripken/emscripten/blob/master/src/embind/embind.js#L907
I now believe it’s possible to eliminate part of the overhead (Function.prototype.bind
) it still wouldn’t be as fast as having direct access to the function.
Some proposals:
- allow function tables to be exported, but frozen. e.g.
return { table_viii: Object.freeze(table_viii) }
- allow export of a new type of function which takes an index and returns the function object. e.g.
return { get_function_viii: function(idx) { return table_viii[idx]; } }
Alon proposed duplicating the function table into the export list with some kind of format that includes the type signature and the index, i.e. “fp_viii_1: some_internal_function” but that would have a rather large code size impact.
Benchmark results: JS → C++ via embind
Can’t figure out how to make a table in Specifiction markdown, so here’s a blockquote:
Firefox 33
Oldcomp / not asm
56636000
Firefox 33
Fastcomp / “almost asm”
52250000
Chrome 38
Oldcomp / not asm
27212000
Firefox 33
Fastcomp / asm.js
10681868
Firefox 33
Oldcomp / asm.js
10657152
Chrome 38
Fastcomp / “almost asm”
3247677
Chrome 38
Fastcomp / asm.js
3234561
Chrome 38
Oldcomp / asm.js
3210571