Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Sync to Async Transformation #1881
Recently I managed to convert one of the most complicated demos of PDCurses, in a clever way (and also a stupid way).
I got a few thoughts on this topic during this terrible experience, and had them posted in this article. Disclaimer: I'm interested but I'm far from an expert in this area. Please forgive me and let me know if some/all of my points are stupid. Thanks!
A plugin/extension should work, somewhat like the closure compiler, as a transformer. But ideally I think it's better integrated into emscripten for optimization reasons, depending on your designs and targets of course.
@kripken I've been mainly using
Generators seem to be slower than callbacks according to jsperf (maybe will be changed in the future), and I'm not sure how generators and task.js could support recursive function calls, seems that they do not save an async stack, but I'm not sure.
It's WIP and only tested on Firefox, I guess it might become a good demo in the future.
The performance is OK (and it's faster on Chrome), although I don't have another to compare with.
referenced this issue
Dec 17, 2013
@ngld There are extra includes and dependencies, for example #ifdef etc. Some macros are specified in the command line parameters. Currently I extract the values and directly use them in js, but I'm afriad that some values might be changed for different configuration.
Maybe there are parameters of clang/g++ to export all the macros? such that I can fee the file to
Does it basically add a last parameter for a continuation in all async functions? Then perhaps for function pointer calls, you can assume they are all async (anything in a function table would be made async)?
Can you elaborate on the problem with the relooper? Perhaps a concrete code sample would help me understand the issue there.
Sorry about the relooper issue, it turns out to be my fault, I did not enable relooper all the time.
The callback function is prepended to the argument list in every definition and call to async functions.
The functions are not transformed unless necessary, as the overhead brought by streamline.js is not negligible.
A little more explanation:
Interesting, thanks. So the runtime used here is the narcissus interpreter? I've been thinking meanwhile about how this could be as close to fast as we could get it, without an interpreter. The best idea I have is the following, let me know what you think and if this overlaps with what you already do:
The main runtime loop manages calling functions, other functions just ask it to and then return, so the callstack is always of depth one.
In theory we could do a partial relooping when there is no synchronous stuff, that should preserve full speed for inner loops without function calls. So perhaps speed would not be that bad here.
No I did not use interpreters, which would be too slow. A function is found to be async if the actual #argument is one more than it should be, e.g.
and in the runtime
The check of
Item 2&3 you mentioned are already taken care of by streamline.js, it maintains both the sync and async stack, and it evens supports exception handling by registering handlers in the frames. See the
Before making an async call, a function registers a callback and exits, the callback is defined during the sync/async transformation. Callback functions are chained through closure but we cannot access it, so we need a separate data structure storing it
There are a few issues I'd like to discuss with you before I actually start:
function pointers w/ asm.js
Deref function pointers with ASM.js is not feasible, I wonder how it can be solved.
utilizing js code pattern
Currently streamline.js can (of course) not understand the label-while-switch structure, so it cannot be reused. I hope this feature could be finally integrated into emscripten as a module, and I'm trying to generate more compact code.
The first one might be more cleaner (?) but the second one is more reliable and faster. However I'm not familiar with the code of emscripten to translate llvm code to js, I just saw uglify is used in
I wonder which one do you prefer?
async function recognition
Currently this is achieved by generating the complete call graph of the whole program, and all the functions that might eventually call an (predefined) async function will be collected (and transformed).
More optimization can be performed without exception and call stack support. If exceptions are not handled,