blob: 1639f49a99f66bb159d9e5d1e8b86856d7ba5def [file] [log] [blame] [edit]
/**
* @license
* Copyright 2014 The Emscripten Authors
* SPDX-License-Identifier: MIT
*/
//
// Async support via ASYNCIFY
//
mergeInto(LibraryManager.library, {
// error handling
$runAndAbortIfError: function(func) {
try {
return func();
} catch (e) {
abort(e);
}
},
#if ASYNCIFY
#if !WASM_BACKEND
/*
* The layout of normal and async stack frames
*
* --------------------- <-- saved sp for the current function
* <last normal stack frame>
* ---------------------
* pointer to the previous frame <-- __async_cur_frame
* saved sp
* callback function <-- ctx, returned by alloc/reallloc, used by the program
* saved local variable1
* saved local variable2
* ...
* --------------------- <-- STACKTOP
*
*/
__async: 0, // whether a truly async function has been called
__async_unwind: 1, // whether to unwind the async stack frame
__async_retval: '{{{ makeStaticAlloc(2) }}}', // store the return value for async functions
__async_cur_frame: 0, // address to the current frame, which stores previous frame, stack pointer and async context
// __async_retval is not actually required in emscripten_async_resume
// but we want it included when ASYNCIFY is enabled
emscripten_async_resume__deps: ['__async', '__async_unwind', '__async_retval', '__async_cur_frame'],
emscripten_async_resume__sig: 'v',
emscripten_async_resume__asm: true,
emscripten_async_resume: function() {
var callback = 0;
___async = 0;
___async_unwind = 1;
while (1) {
if (!___async_cur_frame) return;
callback = {{{ makeGetValueAsm('___async_cur_frame', 8, 'i32') }}};
// the signature of callback is always vi
// the only argument is ctx
{{{ makeDynCall('vi') }}}(callback | 0, (___async_cur_frame + 8)|0);
if (___async) return; // that was an async call
if (!___async_unwind) {
// keep the async stack
___async_unwind = 1;
continue;
}
// unwind normal stack frame
stackRestore({{{ makeGetValueAsm('___async_cur_frame', 4, 'i32') }}});
// pop the last async stack frame
___async_cur_frame = {{{ makeGetValueAsm('___async_cur_frame', 0, 'i32') }}};
}
},
emscripten_sleep__deps: ['emscripten_async_resume', '$Browser'],
emscripten_sleep: function(ms) {
Module['setAsync'](); // tell the scheduler that we have a callback on hold
Browser.safeSetTimeout(_emscripten_async_resume, ms);
},
emscripten_alloc_async_context__deps: ['__async_cur_frame'],
emscripten_alloc_async_context__sig: 'iii',
emscripten_alloc_async_context__asm: true,
emscripten_alloc_async_context: function(len, sp) {
len = len|0;
sp = sp|0;
// len is the size of ctx
// we also need to store prev_frame, stack pointer before ctx
var new_frame = 0; new_frame = stackAlloc((len + 8)|0)|0;
// save sp
{{{ makeSetValueAsm('new_frame', 4, 'sp', 'i32') }}};
// link the frame with previous one
{{{ makeSetValueAsm('new_frame', 0, '___async_cur_frame', 'i32') }}};
___async_cur_frame = new_frame;
return (___async_cur_frame + 8)|0;
},
emscripten_realloc_async_context__deps: ['__async_cur_frame'],
emscripten_realloc_async_context__sig: 'ii',
emscripten_realloc_async_context__asm: true,
emscripten_realloc_async_context: function(len) {
len = len|0;
// assuming that we have on the stacktop
stackRestore(___async_cur_frame | 0);
return ((stackAlloc((len + 8)|0)|0) + 8)|0;
},
emscripten_free_async_context__deps: ['__async_cur_frame'],
emscripten_free_async_context__sig: 'vi',
emscripten_free_async_context__asm: true,
emscripten_free_async_context: function(ctx) {
// this function is called when a possibly async function turned out to be sync
// just undo a recent emscripten_alloc_async_context
ctx = ctx|0;
#if ASSERTIONS
if ((((___async_cur_frame + 8)|0) != (ctx|0))|0) abort();
#endif
stackRestore(___async_cur_frame | 0);
___async_cur_frame = {{{ makeGetValueAsm('___async_cur_frame', 0, 'i32') }}};
},
emscripten_check_async: true,
emscripten_do_not_unwind: true,
emscripten_do_not_unwind_async: true,
emscripten_get_async_return_value_addr__deps: ['__async_retval'],
emscripten_get_async_return_value_addr: true,
/*
* Layout of an ASYNCIFY coroutine structure
*
* 0 callee's async ctx
* 4 callee's STACKTOP
* 8 callee's STACK_MAX
* 12 my async ctx
* 16 my STACKTOP
* 20 my stack size
* 24 coroutine function
* 28 coroutine arg
* 32 my stack:
* ...
*/
emscripten_coroutine_create__sig: 'iiii',
emscripten_coroutine_create__asm: true,
emscripten_coroutine_create__deps: ['malloc', 'emscripten_alloc_async_context'],
emscripten_coroutine_create: function(f, arg, stack_size) {
f = f|0;
arg = arg|0;
stack_size = stack_size|0;
var coroutine = 0;
if ((stack_size|0) <= 0) stack_size = 4096;
coroutine = _malloc(stack_size + 32 | 0) | 0;
{{{ makeSetValueAsm('coroutine', 12, 0, 'i32') }}};
{{{ makeSetValueAsm('coroutine', 16, '(coroutine+32)', 'i32') }}};
{{{ makeSetValueAsm('coroutine', 20, 'stack_size', 'i32') }}};
{{{ makeSetValueAsm('coroutine', 24, 'f', 'i32') }}};
{{{ makeSetValueAsm('coroutine', 28, 'arg', 'i32') }}};
return coroutine|0;
},
emscripten_coroutine_next__sig: 'ii',
emscripten_coroutine_next__asm: true,
emscripten_coroutine_next__deps: ['__async_cur_frame', '__async', 'emscripten_async_resume', 'free'],
emscripten_coroutine_next: function(coroutine) {
coroutine = coroutine|0;
var coroutine_not_finished = 0, temp = 0;
// switch context
{{{ makeSetValueAsm('coroutine', 0, '___async_cur_frame', 'i32') }}};
temp = stackSave() | 0;
{{{ makeSetValueAsm('coroutine', 4, 'temp', 'i32') }}};
{{{ makeSetValueAsm('coroutine', 8, 'STACK_MAX', 'i32') }}};
___async_cur_frame = {{{ makeGetValueAsm('coroutine', 12, 'i32') }}};
stackRestore({{{ makeGetValueAsm('coroutine', 16, 'i32') }}});
STACK_MAX = coroutine + 32 + {{{ makeGetValueAsm('coroutine', 20, 'i32') }}} | 0;
if (!___async_cur_frame) {
// first run
{{{ makeDynCall('vi') }}}(
{{{ makeGetValueAsm('coroutine', 24, 'i32') }}},
{{{ makeGetValueAsm('coroutine', 28, 'i32') }}}
);
} else {
_emscripten_async_resume();
}
// switch context
{{{ makeSetValueAsm('coroutine', 12, '___async_cur_frame', 'i32') }}};
temp = stackSave() | 0;
{{{ makeSetValueAsm('coroutine', 16, 'temp', 'i32') }}};
___async_cur_frame = {{{ makeGetValueAsm('coroutine', 0, 'i32') }}};
stackRestore({{{ makeGetValueAsm('coroutine', 4, 'i32') }}});
STACK_MAX = {{{ makeGetValueAsm('coroutine', 8, 'i32') }}};
coroutine_not_finished = ___async;
if (!coroutine_not_finished) {
// coroutine has finished
_free(coroutine);
}
// 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;
return coroutine_not_finished|0;
},
emscripten_yield__sig: 'v',
emscripten_yield__asm: true,
emscripten_yield: function() {
___async = 1;
},
emscripten_wget__deps: ['emscripten_async_resume', '$PATH_FS', '$Browser'],
emscripten_wget: function(url, file) {
var _url = UTF8ToString(url);
var _file = UTF8ToString(file);
_file = PATH_FS.resolve(FS.cwd(), _file);
Module['setAsync']();
noExitRuntime = true;
var destinationDirectory = PATH.dirname(_file);
FS.createPreloadedFile(
destinationDirectory,
PATH.basename(_file),
_url, true, true,
_emscripten_async_resume,
_emscripten_async_resume,
undefined, // dontCreateFile
undefined, // canOwn
function() { // preFinish
// if the destination directory does not yet exist, create it
FS.mkdirTree(destinationDirectory);
}
);
},
emscripten_fiber_init: function() {
throw 'emscripten_fiber_init is not implemented for fastcomp ASYNCIFY';
},
emscripten_fiber_init_from_current_context: function() {
throw 'emscripten_fiber_init_from_current_context is not implemented for fastcomp ASYNCIFY';
},
emscripten_fiber_swap: function() {
throw 'emscripten_fiber_swap is not implemented for fastcomp ASYNCIFY';
},
#else // !WASM_BACKEND
$Asyncify__deps: ['$Browser', '$runAndAbortIfError'],
$Asyncify: {
State: {
Normal: 0,
Unwinding: 1,
Rewinding: 2
},
state: 0,
StackSize: {{{ ASYNCIFY_STACK_SIZE }}},
currData: null,
// The return value passed to wakeUp() in
// Asyncify.handleSleep(function(wakeUp){...}) is stored here,
// so we can return it later from the C function that called
// Asyncify.handleSleep() after rewinding finishes.
handleSleepReturnValue: 0,
// We must track which wasm exports are called into and
// exited, so that we know where the call stack began,
// which is where we must call to rewind it.
exportCallStack: [],
callStackNameToId: {},
callStackIdToFunc: {},
#if ASYNCIFY_LAZY_LOAD_CODE
callStackIdToName: {},
#endif
callStackId: 0,
afterUnwind: null,
asyncFinalizers: [], // functions to run when *all* asynchronicity is done
sleepCallbacks: [], // functions to call every time we sleep
getCallStackId: function(funcName) {
var id = Asyncify.callStackNameToId[funcName];
if (id === undefined) {
id = Asyncify.callStackId++;
Asyncify.callStackNameToId[funcName] = id;
#if ASYNCIFY_LAZY_LOAD_CODE
Asyncify.callStackIdToName[id] = funcName;
#else
Asyncify.callStackIdToFunc[id] = Module['asm'][funcName];
#endif
}
return id;
},
#if ASSERTIONS
instrumentWasmImports: function(imports) {
var ASYNCIFY_IMPORTS = {{{ JSON.stringify(ASYNCIFY_IMPORTS) }}}.map(function(x) {
return x.split('.')[1];
});
for (var x in imports) {
(function(x) {
var original = imports[x];
if (typeof original === 'function') {
imports[x] = function() {
var originalAsyncifyState = Asyncify.state;
try {
return original.apply(null, arguments);
} finally {
// Only functions in the list of known relevant imports are allowed to change the state.
// Note that invoke_* functions are allowed to change the state if we do not ignore
// indirect calls.
if (Asyncify.state !== originalAsyncifyState &&
ASYNCIFY_IMPORTS.indexOf(x) < 0 &&
!(x.startsWith('invoke_') && {{{ !ASYNCIFY_IGNORE_INDIRECT }}})) {
throw 'import ' + x + ' was not in ASYNCIFY_IMPORTS, but changed the state';
}
}
}
}
})(x);
}
},
#endif
instrumentWasmExports: function(exports) {
var ret = {};
for (var x in exports) {
(function(x) {
var original = exports[x];
if (typeof original === 'function') {
ret[x] = function() {
Asyncify.exportCallStack.push(x);
#if ASYNCIFY_DEBUG >= 2
err('ASYNCIFY: ' + ' '.repeat(Asyncify.exportCallStack.length) + ' try', x);
#endif
try {
return original.apply(null, arguments);
} finally {
if (ABORT) return;
var y = Asyncify.exportCallStack.pop(x);
assert(y === x);
#if ASYNCIFY_DEBUG >= 2
err('ASYNCIFY: ' + ' '.repeat(Asyncify.exportCallStack.length + 1) + ' finally', x);
#endif
if (Asyncify.currData &&
Asyncify.state === Asyncify.State.Unwinding &&
Asyncify.exportCallStack.length === 0) {
// We just finished unwinding.
#if ASYNCIFY_DEBUG
err('ASYNCIFY: stop unwind');
#endif
Asyncify.state = Asyncify.State.Normal;
runAndAbortIfError(Module['_asyncify_stop_unwind']);
if (typeof Fibers !== 'undefined') {
Fibers.trampoline();
}
if (Asyncify.afterUnwind) {
Asyncify.afterUnwind();
Asyncify.afterUnwind = null;
}
}
}
};
} else {
ret[x] = original;
}
})(x);
}
return ret;
},
allocateData: function() {
// An asyncify data structure has three fields:
// 0 current stack pos
// 4 max stack pos
// 8 id of function at bottom of the call stack (callStackIdToFunc[id] == js function)
//
// The Asyncify ABI only interprets the first two fields, the rest is for the runtime.
// We also embed a stack in the same memory region here, right next to the structure.
// This struct is also defined as asyncify_data_t in emscripten/fiber.h
var ptr = _malloc({{{ C_STRUCTS.asyncify_data_s.__size__ }}} + Asyncify.StackSize);
Asyncify.setDataHeader(ptr, ptr + {{{ C_STRUCTS.asyncify_data_s.__size__ }}}, Asyncify.StackSize);
Asyncify.setDataRewindFunc(ptr);
return ptr;
},
setDataHeader: function(ptr, stack, stackSize) {
{{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_ptr, 'stack', 'i32') }}};
{{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_limit, 'stack + stackSize', 'i32') }}};
},
setDataRewindFunc: function(ptr) {
var bottomOfCallStack = Asyncify.exportCallStack[0];
#if ASYNCIFY_DEBUG >= 2
err('ASYNCIFY: setDataRewindFunc('+ptr+'), bottomOfCallStack is', bottomOfCallStack, new Error().stack);
#endif
var rewindId = Asyncify.getCallStackId(bottomOfCallStack);
{{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.rewind_id, 'rewindId', 'i32') }}};
},
getDataRewindFunc: function(ptr) {
var id = {{{ makeGetValue('ptr', C_STRUCTS.asyncify_data_s.rewind_id, 'i32') }}};
var func = Asyncify.callStackIdToFunc[id];
#if ASYNCIFY_LAZY_LOAD_CODE
if (func === undefined) {
func = Module['asm'][Asyncify.callStackIdToName[id]];
Asyncify.callStackIdToFunc[id] = func;
}
#endif
return func;
},
handleSleep: function(startAsync) {
if (ABORT) return;
noExitRuntime = true;
#if ASYNCIFY_DEBUG
err('ASYNCIFY: handleSleep ' + Asyncify.state);
#endif
if (Asyncify.state === Asyncify.State.Normal) {
// Prepare to sleep. Call startAsync, and see what happens:
// if the code decided to call our callback synchronously,
// then no async operation was in fact begun, and we don't
// need to do anything.
var reachedCallback = false;
var reachedAfterCallback = false;
startAsync(function(handleSleepReturnValue) {
#if ASSERTIONS
assert(!handleSleepReturnValue || typeof handleSleepReturnValue === 'number'); // old emterpretify API supported other stuff
#endif
if (ABORT) return;
Asyncify.handleSleepReturnValue = handleSleepReturnValue || 0;
reachedCallback = true;
if (!reachedAfterCallback) {
// We are happening synchronously, so no need for async.
return;
}
#if ASSERTIONS
// This async operation did not happen synchronously, so we did
// unwind. In that case there can be no compiled code on the stack,
// as it might break later operations (we can rewind ok now, but if
// we unwind again, we would unwind through the extra compiled code
// too).
assert(!Asyncify.exportCallStack.length, 'Waking up (starting to rewind) must be done from JS, without compiled code on the stack.');
#endif
#if ASYNCIFY_DEBUG
err('ASYNCIFY: start rewind ' + Asyncify.currData);
#endif
Asyncify.state = Asyncify.State.Rewinding;
runAndAbortIfError(function() { Module['_asyncify_start_rewind'](Asyncify.currData) });
if (Browser.mainLoop.func) {
Browser.mainLoop.resume();
}
var start = Asyncify.getDataRewindFunc(Asyncify.currData);
#if ASYNCIFY_DEBUG
err('ASYNCIFY: start:', start);
#endif
var asyncWasmReturnValue = start();
if (!Asyncify.currData) {
// All asynchronous execution has finished.
// `asyncWasmReturnValue` now contains the final
// return value of the exported async WASM function.
//
// Note: `asyncWasmReturnValue` is distinct from
// `Asyncify.handleSleepReturnValue`.
// `Asyncify.handleSleepReturnValue` contains the return
// value of the last C function to have executed
// `Asyncify.handleSleep()`, where as `asyncWasmReturnValue`
// contains the return value of the exported WASM function
// that may have called C functions that
// call `Asyncify.handleSleep()`.
var asyncFinalizers = Asyncify.asyncFinalizers;
Asyncify.asyncFinalizers = [];
asyncFinalizers.forEach(function(func) {
func(asyncWasmReturnValue);
});
}
});
reachedAfterCallback = true;
if (!reachedCallback) {
// A true async operation was begun; start a sleep.
Asyncify.state = Asyncify.State.Unwinding;
// TODO: reuse, don't alloc/free every sleep
Asyncify.currData = Asyncify.allocateData();
#if ASYNCIFY_DEBUG
err('ASYNCIFY: start unwind ' + Asyncify.currData);
#endif
runAndAbortIfError(function() { Module['_asyncify_start_unwind'](Asyncify.currData) });
if (Browser.mainLoop.func) {
Browser.mainLoop.pause();
}
}
} else if (Asyncify.state === Asyncify.State.Rewinding) {
// Stop a resume.
#if ASYNCIFY_DEBUG
err('ASYNCIFY: stop rewind');
#endif
Asyncify.state = Asyncify.State.Normal;
runAndAbortIfError(Module['_asyncify_stop_rewind']);
_free(Asyncify.currData);
Asyncify.currData = null;
// Call all sleep callbacks now that the sleep-resume is all done.
Asyncify.sleepCallbacks.forEach(function(func) {
func();
});
} else {
abort('invalid state: ' + Asyncify.state);
}
return Asyncify.handleSleepReturnValue;
}
},
emscripten_sleep: function(ms) {
Asyncify.handleSleep(function(wakeUp) {
Browser.safeSetTimeout(wakeUp, ms);
});
},
emscripten_wget__deps: ['$PATH_FS', '$FS'],
emscripten_wget: function(url, file) {
Asyncify.handleSleep(function(wakeUp) {
var _url = UTF8ToString(url);
var _file = UTF8ToString(file);
_file = PATH_FS.resolve(FS.cwd(), _file);
var destinationDirectory = PATH.dirname(_file);
FS.createPreloadedFile(
destinationDirectory,
PATH.basename(_file),
_url, true, true,
wakeUp,
wakeUp,
undefined, // dontCreateFile
undefined, // canOwn
function() { // preFinish
// if the destination directory does not yet exist, create it
FS.mkdirTree(destinationDirectory);
}
);
});
},
emscripten_wget_data: function(url, pbuffer, pnum, perror) {
Asyncify.handleSleep(function(wakeUp) {
Browser.asyncLoad(UTF8ToString(url), function(byteArray) {
// can only allocate the buffer after the wakeUp, not during an asyncing
var buffer = _malloc(byteArray.length); // must be freed by caller!
HEAPU8.set(byteArray, buffer);
{{{ makeSetValueAsm('pbuffer', 0, 'buffer', 'i32') }}};
{{{ makeSetValueAsm('pnum', 0, 'byteArray.length', 'i32') }}};
{{{ makeSetValueAsm('perror', 0, '0', 'i32') }}};
wakeUp();
}, function() {
{{{ makeSetValueAsm('perror', 0, '1', 'i32') }}};
wakeUp();
}, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
});
},
emscripten_scan_registers: function(func) {
Asyncify.handleSleep(function(wakeUp) {
// We must first unwind, so things are spilled to the stack. We
// can resume right after unwinding, no need for a timeout.
Asyncify.afterUnwind = function() {
{{{ makeDynCall('vii') }}}(func, Asyncify.currData + 8, HEAP32[Asyncify.currData >> 2]);
wakeUp();
};
});
},
emscripten_lazy_load_code: function() {
Asyncify.handleSleep(function(wakeUp) {
// Update the expected wasm binary file to be the lazy one.
wasmBinaryFile += '.lazy.wasm';
// Add a callback for when all run dependencies are fulfilled, which happens when async wasm loading is done.
dependenciesFulfilled = wakeUp;
// Load the new wasm.
asm = createWasm();
});
},
$Fibers__deps: ['$Asyncify'],
$Fibers: {
nextFiber: 0,
trampolineRunning: false,
trampoline: function() {
if (!Fibers.trampolineRunning && Fibers.nextFiber) {
Fibers.trampolineRunning = true;
do {
var fiber = Fibers.nextFiber;
Fibers.nextFiber = 0;
#if ASYNCIFY_DEBUG >= 2
err("ASYNCIFY/FIBER: trampoline jump into fiber", fiber, new Error().stack);
#endif
Fibers.finishContextSwitch(fiber);
} while (Fibers.nextFiber);
Fibers.trampolineRunning = false;
}
},
/*
* NOTE: This function is the asynchronous part of emscripten_fiber_swap.
*/
finishContextSwitch: function(newFiber) {
STACK_BASE = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'i32') }}};
STACK_MAX = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'i32') }}};
#if WASM_BACKEND && STACK_OVERFLOW_CHECK >= 2
Module['___set_stack_limit'](STACK_MAX);
#endif
stackRestore({{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'i32') }}});
var entryPoint = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, 'i32') }}};
if (entryPoint !== 0) {
#if STACK_OVERFLOW_CHECK
writeStackCookie();
#endif
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: entering fiber', newFiber, 'for the first time');
#endif
Asyncify.currData = null;
{{{ makeSetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, 0, 'i32') }}};
var userData = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.user_data, 'i32') }}};
{{{ makeDynCall('vi') }}}(entryPoint, userData);
} else {
var asyncifyData = newFiber + 20;
Asyncify.currData = asyncifyData;
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: start rewind', asyncifyData, '(resuming fiber', newFiber, ')');
#endif
Asyncify.state = Asyncify.State.Rewinding;
Module['_asyncify_start_rewind'](asyncifyData);
var start = Asyncify.getDataRewindFunc(asyncifyData);
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: start: ' + start);
#endif
start();
}
},
},
emscripten_fiber_init__sig: 'viiiiiii',
emscripten_fiber_init__deps: ['$Asyncify'],
emscripten_fiber_init: function(fiber, entryPoint, userData, cStack, cStackSize, asyncStack, asyncStackSize) {
var cStackBase = cStack + cStackSize;
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'cStackBase', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'cStack', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'cStackBase', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.entry, 'entryPoint', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.user_data, 'userData', 'i32') }}};
var asyncifyData = fiber + {{{ C_STRUCTS.emscripten_fiber_s.asyncify_data }}};
Asyncify.setDataHeader(asyncifyData, asyncStack, asyncStackSize);
},
emscripten_fiber_init_from_current_context__sig: 'vii',
emscripten_fiber_init_from_current_context__deps: ['$Asyncify'],
emscripten_fiber_init_from_current_context: function(fiber, asyncStack, asyncStackSize) {
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'STACK_BASE', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'STACK_MAX', 'i32') }}};
{{{ makeSetValue('fiber', C_STRUCTS.emscripten_fiber_s.entry, 0, 'i32') }}};
var asyncifyData = fiber + {{{ C_STRUCTS.emscripten_fiber_s.asyncify_data }}};
Asyncify.setDataHeader(asyncifyData, asyncStack, asyncStackSize);
},
emscripten_fiber_swap__sig: 'vii',
emscripten_fiber_swap__deps: ["$Asyncify", "$Fibers"],
emscripten_fiber_swap: function(oldFiber, newFiber) {
if (ABORT) return;
noExitRuntime = true;
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: swap', oldFiber, '->', newFiber, 'state:', Asyncify.state);
#endif
if (Asyncify.state === Asyncify.State.Normal) {
Asyncify.state = Asyncify.State.Unwinding;
var asyncifyData = oldFiber + {{{ C_STRUCTS.emscripten_fiber_s.asyncify_data }}};
Asyncify.setDataRewindFunc(asyncifyData);
Asyncify.currData = asyncifyData;
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: start unwind', asyncifyData);
#endif
Module['_asyncify_start_unwind'](asyncifyData);
var stackTop = stackSave();
{{{ makeSetValue('oldFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'stackTop', 'i32') }}};
Fibers.nextFiber = newFiber;
} else {
#if ASSERTIONS
assert(Asyncify.state === Asyncify.State.Rewinding);
#endif
#if ASYNCIFY_DEBUG
err('ASYNCIFY/FIBER: stop rewind');
#endif
Asyncify.state = Asyncify.State.Normal;
Module['_asyncify_stop_rewind']();
Asyncify.currData = null;
}
},
emscripten_coroutine_create: function() {
throw 'emscripten_coroutine_create has been removed. Please use the Fibers API';
},
emscripten_coroutine_next: function() {
throw 'emscripten_coroutine_next has been removed. Please use the Fibers API';
},
emscripten_yield: function() {
throw 'emscripten_yield has been removed. Please use the Fibers API';
},
#endif
#else // ASYNCIFY
emscripten_sleep: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_sleep';
},
emscripten_coroutine_create: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_coroutine_create';
},
emscripten_coroutine_next: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_coroutine_next';
},
emscripten_yield: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_yield';
},
emscripten_wget: function(url, file) {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_wget';
},
emscripten_wget_data: function(url, file) {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_wget_data';
},
emscripten_scan_registers: function(url, file) {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_scan_registers';
},
emscripten_fiber_init: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init';
},
emscripten_fiber_init_from_current_context: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init_from_current_context';
},
emscripten_fiber_swap: function() {
throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_swap';
},
#endif // ASYNCIFY
});
if (WASM_BACKEND && ASYNCIFY) {
DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push('$Asyncify');
}