// coroutine may be created during an async function
// we do not want to affect the original async ctx
// strictly we should backup and restore ___async, ___async_retval and ___async_unwind
// but ___async=0 seems enough
___async=0;
returncoroutine_not_finished|0;
},
emscripten_yield__sig: 'v',
emscripten_yield__asm: true,
emscripten_yield: function(){
___async=1;
}
#else // ASYNCIFY
#if EMTERPRETIFY_ASYNC
// Emterpreter sync=>async support
//
// The idea here is that almost all interpreter frames are already on the stack (the
// emterpreter stack), so it's easy to save a callstack and reload it, we just need
// to also save the pc.
// Saving state keeps the pc right before the current call. That means when we reload,
// we are going to re-call in the exact same way as before - including the final call
// to the async function here! Therefore sleep etc. detect the state, so they know
// if they are the first call or the second. The second typically does nothing, but
// if there is a return value it could return it, etc.
$EmterpreterAsync__deps: ['$Browser'],
$EmterpreterAsync: {
initted: false,
state: 0,// 0 - nothing/normal
// 1 - saving the stack: functions should all be in emterpreter, and should all save&exit/return
// 2 - restoring the stack: functions should all be in emterpreter, and should all restore&continue
// 3 - during sleep. this is between 1 and 2. at this time it is ok to call yield funcs
saveStack: '',
yieldCallbacks: [],
postAsync: null,
asyncFinalizers: [],// functions to run when all asynchronicity is done
ensureInit: function(){
if(this.initted)return;
this.initted=true;
#if ASSERTIONS
abortDecorators.push(function(output,what){
if(EmterpreterAsync.state!==0){
returnoutput+'\nThis error happened during an emterpreter-async save or load of the stack. Was there non-emterpreted code on the stack during save (which is unallowed)? You may want to adjust EMTERPRETIFY_BLACKLIST, EMTERPRETIFY_WHITELIST.\nThis is what the stack looked like when we tried to save it: '+[EmterpreterAsync.state,EmterpreterAsync.saveStack];
}
returnoutput;
});
#endif
},
setState: function(s){
this.ensureInit();
this.state=s;
asm.setAsyncState(s);
},
handle: function(doAsyncOp,yieldDuring){
Module['noExitRuntime']=true;
if(EmterpreterAsync.state===0){
// save the stack we want to resume. this lets other code run in between
// XXX this assumes that this stack top never ever leak! exceptions might violate that
assert(stacktop===asm.stackSave());// nothing should have modified the stack meanwhile
#endif
EmterpreterAsync.setState(2);
// Resume the main loop
if(Browser.mainLoop.func){
Browser.mainLoop.resume();
}
assert(!EmterpreterAsync.postAsync);
EmterpreterAsync.postAsync=post||null;
asm.emterpret(stack[0]);// pc of the first function, from which we can reconstruct the rest, is at position 0 on the stack
if(!yieldDuring&&EmterpreterAsync.state===0){
// if we did *not* do another async operation, then we know that nothing is conceptually on the stack now, and we can re-allow async callbacks as well as run the queued ones right now