Commit 6c9cbc11 authored by Michael Droettboom's avatar Michael Droettboom Committed by GitHub

Merge pull request #89 from mdboom/update-emscripten

Update emscripten to 1.38.10
parents 757725bf b3d8e4c2
PYODIDE_ROOT=$(abspath .) PYODIDE_ROOT=$(abspath .)
include Makefile.envs include Makefile.envs
FILEPACKAGER=emsdk/emsdk/emscripten/tag-1.38.4/tools/file_packager.py FILEPACKAGER=emsdk/emsdk/emscripten/tag-1.38.10/tools/file_packager.py
CPYTHONROOT=cpython CPYTHONROOT=cpython
CPYTHONLIB=$(CPYTHONROOT)/installs/python-$(PYVERSION)/lib/python$(PYMINOR) CPYTHONLIB=$(CPYTHONROOT)/installs/python-$(PYVERSION)/lib/python$(PYMINOR)
...@@ -25,7 +25,7 @@ LDFLAGS=\ ...@@ -25,7 +25,7 @@ LDFLAGS=\
-s MAIN_MODULE=1 \ -s MAIN_MODULE=1 \
-s EMULATED_FUNCTION_POINTERS=1 \ -s EMULATED_FUNCTION_POINTERS=1 \
-s EMULATE_FUNCTION_POINTER_CASTS=1 \ -s EMULATE_FUNCTION_POINTER_CASTS=1 \
-s EXPORTED_FUNCTIONS='["_main", "__ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv"]' \ -s EXPORTED_FUNCTIONS='["_main", "__ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv", "__ZNSt11logic_errorC2EPKc"]' \
-s WASM=1 \ -s WASM=1 \
-s SWAPPABLE_ASM_MODULE=1 \ -s SWAPPABLE_ASM_MODULE=1 \
-s USE_FREETYPE=1 \ -s USE_FREETYPE=1 \
......
export PATH := $(PYODIDE_ROOT)/ccache:$(PYODIDE_ROOT)/emsdk/emsdk:$(PYODIDE_ROOT)/emsdk/emsdk/clang/tag-e-1.38.4/build_tag-e1.38.4_64/bin:$(PYODIDE_ROOT)/emsdk/emsdk/node/8.9.1_64bit/bin:$(PYODIDE_ROOT)/emsdk/emsdk/emscripten/tag-1.38.4:$(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.4_64bit_binaryen/bin:$(PATH) export PATH := $(PYODIDE_ROOT)/ccache:$(PYODIDE_ROOT)/emsdk/emsdk:$(PYODIDE_ROOT)/emsdk/emsdk/clang/tag-e-1.38.10/build_tag-e1.38.10_64/bin:$(PYODIDE_ROOT)/emsdk/emsdk/node/8.9.1_64bit/bin:$(PYODIDE_ROOT)/emsdk/emsdk/emscripten/tag-1.38.10:$(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.10_64bit_binaryen/bin:$(PATH)
export EMSDK = $(PYODIDE_ROOT)/emsdk/emsdk export EMSDK = $(PYODIDE_ROOT)/emsdk/emsdk
export EM_CONFIG = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten export EM_CONFIG = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten
export EM_CACHE = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten_cache export EM_CACHE = $(PYODIDE_ROOT)/emsdk/emsdk/.emscripten_cache
export EMSCRIPTEN = $(PYODIDE_ROOT)/emsdk/emsdk/emscripten/tag-1.38.4 export EMSCRIPTEN = $(PYODIDE_ROOT)/emsdk/emsdk/emscripten/tag-1.38.10
export BINARYEN_ROOT = $(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.4_64bit_binaryen export BINARYEN_ROOT = $(PYODIDE_ROOT)/emsdk/emsdk/binaryen/tag-1.38.10_64bit_binaryen
export PYVERSION=3.6.4 export PYVERSION=3.6.4
export PYMINOR=$(basename $(PYVERSION)) export PYMINOR=$(basename $(PYVERSION))
......
...@@ -9,15 +9,13 @@ emsdk/.complete: ...@@ -9,15 +9,13 @@ emsdk/.complete:
sed -i -e "s#CPU_CORES = max(multiprocessing.cpu_count()-1, 1)#CPU_CORES = 3#g" emsdk/emsdk sed -i -e "s#CPU_CORES = max(multiprocessing.cpu_count()-1, 1)#CPU_CORES = 3#g" emsdk/emsdk
( \ ( \
cd emsdk ; \ cd emsdk ; \
./emsdk install --build=Release sdk-tag-1.38.4-64bit binaryen-tag-1.38.4-64bit ; \ ./emsdk install --build=Release sdk-tag-1.38.10-64bit binaryen-tag-1.38.10-64bit ; \
cd .. ; \ cd .. ; \
(cat patches/*.patch | patch -p1) ; \ (cat patches/*.patch | patch -p1) ; \
cp files/* emsdk/emscripten/tag-1.38.4/src/ ; \ cd emsdk/binaryen/tag-1.38.10_64bit_binaryen/ ; \
cd emsdk/binaryen/tag-1.38.4_64bit_binaryen/ ; \
make ; \ make ; \
cd ../.. ; \ cd ../.. ; \
cp binaryen/tag-1.38.4/bin/binaryen.js binaryen/tag-1.38.4_64bit_binaryen/bin ; \ ./emsdk activate --embedded --build=Release sdk-tag-1.38.10-64bit binaryen-tag-1.38.10-64bit ; \
./emsdk activate --embedded --build=Release sdk-tag-1.38.4-64bit binaryen-tag-1.38.4-64bit ; \
touch .complete \ touch .complete \
) )
......
This source diff could not be displayed because it is too large. You can view the blob instead.
//"use strict";
// Utilities for browser environments
var LibraryBrowser = {
$Browser__deps: ['emscripten_set_main_loop', 'emscripten_set_main_loop_timing'],
$Browser__postset: 'Module["requestFullScreen"] = function Module_requestFullScreen(lockPointer, resizeCanvas, vrDevice) { Module.printErr("Module.requestFullScreen is deprecated. Please call Module.requestFullscreen instead."); Module["requestFullScreen"] = Module["requestFullscreen"]; Browser.requestFullScreen(lockPointer, resizeCanvas, vrDevice) };\n' + // exports
'Module["requestFullscreen"] = function Module_requestFullscreen(lockPointer, resizeCanvas, vrDevice) { Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice) };\n' + // exports
'Module["requestAnimationFrame"] = function Module_requestAnimationFrame(func) { Browser.requestAnimationFrame(func) };\n' +
'Module["setCanvasSize"] = function Module_setCanvasSize(width, height, noUpdates) { Browser.setCanvasSize(width, height, noUpdates) };\n' +
'Module["pauseMainLoop"] = function Module_pauseMainLoop() { Browser.mainLoop.pause() };\n' +
'Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() };\n' +
'Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }\n' +
'Module["createContext"] = function Module_createContext(canvas, useWebGL, setInModule, webGLContextAttributes) { return Browser.createContext(canvas, useWebGL, setInModule, webGLContextAttributes) }',
$Browser: {
mainLoop: {
scheduler: null,
method: '',
// Each main loop is numbered with a ID in sequence order. Only one main loop can run at a time. This variable stores the ordinal number of the main loop that is currently
// allowed to run. All previous main loops will quit themselves. This is incremented whenever a new main loop is created.
currentlyRunningMainloop: 0,
func: null, // The main loop tick function that will be called at each iteration.
arg: 0, // The argument that will be passed to the main loop. (of type void*)
timingMode: 0,
timingValue: 0,
currentFrameNumber: 0,
queue: [],
pause: function() {
Browser.mainLoop.scheduler = null;
Browser.mainLoop.currentlyRunningMainloop++; // Incrementing this signals the previous main loop that it's now become old, and it must return.
},
resume: function() {
Browser.mainLoop.currentlyRunningMainloop++;
var timingMode = Browser.mainLoop.timingMode;
var timingValue = Browser.mainLoop.timingValue;
var func = Browser.mainLoop.func;
Browser.mainLoop.func = null;
_emscripten_set_main_loop(func, 0, false, Browser.mainLoop.arg, true /* do not set timing and call scheduler, we will do it on the next lines */);
_emscripten_set_main_loop_timing(timingMode, timingValue);
Browser.mainLoop.scheduler();
},
updateStatus: function() {
if (Module['setStatus']) {
var message = Module['statusMessage'] || 'Please wait...';
var remaining = Browser.mainLoop.remainingBlockers;
var expected = Browser.mainLoop.expectedBlockers;
if (remaining) {
if (remaining < expected) {
Module['setStatus'](message + ' (' + (expected - remaining) + '/' + expected + ')');
} else {
Module['setStatus'](message);
}
} else {
Module['setStatus']('');
}
}
},
runIter: function(func) {
if (ABORT) return;
if (Module['preMainLoop']) {
var preRet = Module['preMainLoop']();
if (preRet === false) {
return; // |return false| skips a frame
}
}
try {
func();
} catch (e) {
if (e instanceof ExitStatus) {
return;
} else {
if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]);
throw e;
}
}
if (Module['postMainLoop']) Module['postMainLoop']();
}
},
isFullscreen: false,
pointerLock: false,
moduleContextCreatedCallbacks: [],
workers: [],
init: function() {
if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers
if (Browser.initted) return;
Browser.initted = true;
try {
new Blob();
Browser.hasBlobConstructor = true;
} catch(e) {
Browser.hasBlobConstructor = false;
console.log("warning: no blob constructor, cannot create blobs with mimetypes");
}
Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? console.log("warning: no BlobBuilder") : null));
Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined;
if (!Module.noImageDecoding && typeof Browser.URLObject === 'undefined') {
console.log("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");
Module.noImageDecoding = true;
}
// Support for plugins that can process preloaded files. You can add more of these to
// your app by creating and appending to Module.preloadPlugins.
//
// Each plugin is asked if it can handle a file based on the file's name. If it can,
// it is given the file's raw data. When it is done, it calls a callback with the file's
// (possibly modified) data. For example, a plugin might decompress a file, or it
// might create some side data structure for use later (like an Image element, etc.).
var imagePlugin = {};
imagePlugin['canHandle'] = function imagePlugin_canHandle(name) {
return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
};
imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) {
var b = null;
if (Browser.hasBlobConstructor) {
try {
b = new Blob([byteArray], { type: Browser.getMimetype(name) });
if (b.size !== byteArray.length) { // Safari bug #118630
// Safari's Blob can only take an ArrayBuffer
b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
}
} catch(e) {
warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
}
}
if (!b) {
var bb = new Browser.BlobBuilder();
bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range
b = bb.getBlob();
}
var url = Browser.URLObject.createObjectURL(b);
#if ASSERTIONS
assert(typeof url == 'string', 'createObjectURL must return a url as a string');
#endif
var img = new Image();
img.onload = function img_onload() {
assert(img.complete, 'Image ' + name + ' could not be decoded');
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
Module["preloadedImages"][name] = canvas;
Browser.URLObject.revokeObjectURL(url);
if (onload) onload(byteArray);
};
img.onerror = function img_onerror(event) {
console.log('Image ' + url + ' could not be decoded');
if (onerror) onerror();
};
img.src = url;
};
Module['preloadPlugins'].push(imagePlugin);
var audioPlugin = {};
audioPlugin['canHandle'] = function audioPlugin_canHandle(name) {
return !Module.noAudioDecoding && name.substr(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 };
};
audioPlugin['handle'] = function audioPlugin_handle(byteArray, name, onload, onerror) {
var done = false;
function finish(audio) {
if (done) return;
done = true;
Module["preloadedAudios"][name] = audio;
if (onload) onload(byteArray);
}
function fail() {
if (done) return;
done = true;
Module["preloadedAudios"][name] = new Audio(); // empty shim
if (onerror) onerror();
}
if (Browser.hasBlobConstructor) {
try {
var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
} catch(e) {
return fail();
}
var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this!
#if ASSERTIONS
assert(typeof url == 'string', 'createObjectURL must return a url as a string');
#endif
var audio = new Audio();
audio.addEventListener('canplaythrough', function() { finish(audio) }, false); // use addEventListener due to chromium bug 124926
audio.onerror = function audio_onerror(event) {
if (done) return;
console.log('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach');
function encode64(data) {
var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var PAD = '=';
var ret = '';
var leftchar = 0;
var leftbits = 0;
for (var i = 0; i < data.length; i++) {
leftchar = (leftchar << 8) | data[i];
leftbits += 8;
while (leftbits >= 6) {
var curr = (leftchar >> (leftbits-6)) & 0x3f;
leftbits -= 6;
ret += BASE[curr];
}
}
if (leftbits == 2) {
ret += BASE[(leftchar&3) << 4];
ret += PAD + PAD;
} else if (leftbits == 4) {
ret += BASE[(leftchar&0xf) << 2];
ret += PAD;
}
return ret;
}
audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray);
finish(audio); // we don't wait for confirmation this worked - but it's worth trying
};
audio.src = url;
// workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror
Browser.safeSetTimeout(function() {
finish(audio); // try to use it even though it is not necessarily ready to play
}, 10000);
} else {
return fail();
}
};
Module['preloadPlugins'].push(audioPlugin);
#if (WASM != 0) && (MAIN_MODULE != 0)
var wasmPlugin = {};
wasmPlugin['asyncWasmLoadPromise'] = new Promise(
function(resolve, reject) { return resolve(); });
wasmPlugin['canHandle'] = function(name) {
return !Module.noWasmDecoding && (name.endsWith('.so') || name.endsWith('.wasm'));
};
wasmPlugin['handle'] = function(byteArray, name, onload, onerror) {
// loadWebAssemblyModule can not load modules out-of-order, so rather
// than just running the promises in parallel, this makes a chain of
// promises to run in series.
this.asyncWasmLoadPromise = this.asyncWasmLoadPromise.then(
function() {
return Module.loadWebAssemblyModule(byteArray, true)
}).then(
function(module) {
Module.preloadedWasm[name] = module;
onload();
},
function(err) {
console.warn("Couldn't instantiate wasm: " + name + " '" + err + "'");
onerror();
});
};
Module['preloadPlugins'].push(wasmPlugin);
#endif
// Canvas event setup
function pointerLockChange() {
Browser.pointerLock = document['pointerLockElement'] === Module['canvas'] ||
document['mozPointerLockElement'] === Module['canvas'] ||
document['webkitPointerLockElement'] === Module['canvas'] ||
document['msPointerLockElement'] === Module['canvas'];
}
var canvas = Module['canvas'];
if (canvas) {
// forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module
// Module['forcedAspectRatio'] = 4 / 3;
canvas.requestPointerLock = canvas['requestPointerLock'] ||
canvas['mozRequestPointerLock'] ||
canvas['webkitRequestPointerLock'] ||
canvas['msRequestPointerLock'] ||
function(){};
canvas.exitPointerLock = document['exitPointerLock'] ||
document['mozExitPointerLock'] ||
document['webkitExitPointerLock'] ||
document['msExitPointerLock'] ||
function(){}; // no-op if function does not exist
canvas.exitPointerLock = canvas.exitPointerLock.bind(document);
document.addEventListener('pointerlockchange', pointerLockChange, false);
document.addEventListener('mozpointerlockchange', pointerLockChange, false);
document.addEventListener('webkitpointerlockchange', pointerLockChange, false);
document.addEventListener('mspointerlockchange', pointerLockChange, false);
if (Module['elementPointerLock']) {
canvas.addEventListener("click", function(ev) {
if (!Browser.pointerLock && Module['canvas'].requestPointerLock) {
Module['canvas'].requestPointerLock();
ev.preventDefault();
}
}, false);
}
}
},
createContext: function(canvas, useWebGL, setInModule, webGLContextAttributes) {
if (useWebGL && Module.ctx && canvas == Module.canvas) return Module.ctx; // no need to recreate GL context if it's already been created for this canvas.
var ctx;
var contextHandle;
if (useWebGL) {
// For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults.
var contextAttributes = {
antialias: false,
alpha: false
};
if (webGLContextAttributes) {
for (var attribute in webGLContextAttributes) {
contextAttributes[attribute] = webGLContextAttributes[attribute];
}
}
contextHandle = GL.createContext(canvas, contextAttributes);
if (contextHandle) {
ctx = GL.getContext(contextHandle).GLctx;
}
} else {
ctx = canvas.getContext('2d');
}
if (!ctx) return null;
if (setInModule) {
if (!useWebGL) assert(typeof GLctx === 'undefined', 'cannot set in module if GLctx is used, but we are a non-GL context that would replace it');
Module.ctx = ctx;
if (useWebGL) GL.makeContextCurrent(contextHandle);
Module.useWebGL = useWebGL;
Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() });
Browser.init();
}
return ctx;
},
destroyContext: function(canvas, useWebGL, setInModule) {},
fullscreenHandlersInstalled: false,
lockPointer: undefined,
resizeCanvas: undefined,
requestFullscreen: function(lockPointer, resizeCanvas, vrDevice) {
Browser.lockPointer = lockPointer;
Browser.resizeCanvas = resizeCanvas;
Browser.vrDevice = vrDevice;
if (typeof Browser.lockPointer === 'undefined') Browser.lockPointer = true;
if (typeof Browser.resizeCanvas === 'undefined') Browser.resizeCanvas = false;
if (typeof Browser.vrDevice === 'undefined') Browser.vrDevice = null;
var canvas = Module['canvas'];
function fullscreenChange() {
Browser.isFullscreen = false;
var canvasContainer = canvas.parentNode;
if ((document['fullscreenElement'] || document['mozFullScreenElement'] ||
document['msFullscreenElement'] || document['webkitFullscreenElement'] ||
document['webkitCurrentFullScreenElement']) === canvasContainer) {
canvas.exitFullscreen = document['exitFullscreen'] ||
document['cancelFullScreen'] ||
document['mozCancelFullScreen'] ||
document['msExitFullscreen'] ||
document['webkitCancelFullScreen'] ||
function() {};
canvas.exitFullscreen = canvas.exitFullscreen.bind(document);
if (Browser.lockPointer) canvas.requestPointerLock();
Browser.isFullscreen = true;
if (Browser.resizeCanvas) {
Browser.setFullscreenCanvasSize();
} else {
Browser.updateCanvasDimensions(canvas);
}
} else {
// remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen
canvasContainer.parentNode.insertBefore(canvas, canvasContainer);
canvasContainer.parentNode.removeChild(canvasContainer);
if (Browser.resizeCanvas) {
Browser.setWindowedCanvasSize();
} else {
Browser.updateCanvasDimensions(canvas);
}
}
if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullscreen);
if (Module['onFullscreen']) Module['onFullscreen'](Browser.isFullscreen);
}
if (!Browser.fullscreenHandlersInstalled) {
Browser.fullscreenHandlersInstalled = true;
document.addEventListener('fullscreenchange', fullscreenChange, false);
document.addEventListener('mozfullscreenchange', fullscreenChange, false);
document.addEventListener('webkitfullscreenchange', fullscreenChange, false);
document.addEventListener('MSFullscreenChange', fullscreenChange, false);
}
// create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root
var canvasContainer = document.createElement("div");
canvas.parentNode.insertBefore(canvasContainer, canvas);
canvasContainer.appendChild(canvas);
// use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size)
canvasContainer.requestFullscreen = canvasContainer['requestFullscreen'] ||
canvasContainer['mozRequestFullScreen'] ||
canvasContainer['msRequestFullscreen'] ||
(canvasContainer['webkitRequestFullscreen'] ? function() { canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null) ||
(canvasContainer['webkitRequestFullScreen'] ? function() { canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) } : null);
if (vrDevice) {
canvasContainer.requestFullscreen({ vrDisplay: vrDevice });
} else {
canvasContainer.requestFullscreen();
}
},
requestFullScreen: function(lockPointer, resizeCanvas, vrDevice) {
Module.printErr('Browser.requestFullScreen() is deprecated. Please call Browser.requestFullscreen instead.');
Browser.requestFullScreen = function(lockPointer, resizeCanvas, vrDevice) {
return Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice);
}
return Browser.requestFullscreen(lockPointer, resizeCanvas, vrDevice);
},
nextRAF: 0,
fakeRequestAnimationFrame: function(func) {
// try to keep 60fps between calls to here
var now = Date.now();
if (Browser.nextRAF === 0) {
Browser.nextRAF = now + 1000/60;
} else {
while (now + 2 >= Browser.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0
Browser.nextRAF += 1000/60;
}
}
var delay = Math.max(Browser.nextRAF - now, 0);
setTimeout(func, delay);
},
requestAnimationFrame: function requestAnimationFrame(func) {
if (typeof window === 'undefined') { // Provide fallback to setTimeout if window is undefined (e.g. in Node.js)
Browser.fakeRequestAnimationFrame(func);
} else {
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = window['requestAnimationFrame'] ||
window['mozRequestAnimationFrame'] ||
window['webkitRequestAnimationFrame'] ||
window['msRequestAnimationFrame'] ||
window['oRequestAnimationFrame'] ||
Browser.fakeRequestAnimationFrame;
}
window.requestAnimationFrame(func);
}
},
// generic abort-aware wrapper for an async callback
safeCallback: function(func) {
return function() {
if (!ABORT) return func.apply(null, arguments);
};
},
// abort and pause-aware versions TODO: build main loop on top of this?
allowAsyncCallbacks: true,
queuedAsyncCallbacks: [],
pauseAsyncCallbacks: function() {
Browser.allowAsyncCallbacks = false;
},
resumeAsyncCallbacks: function() { // marks future callbacks as ok to execute, and synchronously runs any remaining ones right now
Browser.allowAsyncCallbacks = true;
if (Browser.queuedAsyncCallbacks.length > 0) {
var callbacks = Browser.queuedAsyncCallbacks;
Browser.queuedAsyncCallbacks = [];
callbacks.forEach(function(func) {
func();
});
}
},
safeRequestAnimationFrame: function(func) {
return Browser.requestAnimationFrame(function() {
if (ABORT) return;
if (Browser.allowAsyncCallbacks) {
func();
} else {
Browser.queuedAsyncCallbacks.push(func);
}
});
},
safeSetTimeout: function(func, timeout) {
Module['noExitRuntime'] = true;
return setTimeout(function() {
if (ABORT) return;
if (Browser.allowAsyncCallbacks) {
func();
} else {
Browser.queuedAsyncCallbacks.push(func);
}
}, timeout);
},
safeSetInterval: function(func, timeout) {
Module['noExitRuntime'] = true;
return setInterval(function() {
if (ABORT) return;
if (Browser.allowAsyncCallbacks) {
func();
} // drop it on the floor otherwise, next interval will kick in
}, timeout);
},
getMimetype: function(name) {
return {
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'bmp': 'image/bmp',
'ogg': 'audio/ogg',
'wav': 'audio/wav',
'mp3': 'audio/mpeg'
}[name.substr(name.lastIndexOf('.')+1)];
},
getUserMedia: function(func) {
if(!window.getUserMedia) {
window.getUserMedia = navigator['getUserMedia'] ||
navigator['mozGetUserMedia'];
}
window.getUserMedia(func);
},
getMovementX: function(event) {
return event['movementX'] ||
event['mozMovementX'] ||
event['webkitMovementX'] ||
0;
},
getMovementY: function(event) {
return event['movementY'] ||
event['mozMovementY'] ||
event['webkitMovementY'] ||
0;
},
// Browsers specify wheel direction according to the page CSS pixel Y direction:
// Scrolling mouse wheel down (==towards user/away from screen) on Windows/Linux (and OSX without 'natural scroll' enabled)
// is the positive wheel direction. Scrolling mouse wheel up (towards the screen) is the negative wheel direction.
// This function returns the wheel direction in the browser page coordinate system (+: down, -: up). Note that this is often the
// opposite of native code: In native APIs the positive scroll direction is to scroll up (away from the user).
// NOTE: The mouse wheel delta is a decimal number, and can be a fractional value within -1 and 1. If you need to represent
// this as an integer, don't simply cast to int, or you may receive scroll events for wheel delta == 0.
getMouseWheelDelta: function(event) {
var delta = 0;
switch (event.type) {
case 'DOMMouseScroll':
delta = event.detail;
break;
case 'mousewheel':
delta = event.wheelDelta;
break;
case 'wheel':
delta = event['deltaY'];
break;
default:
throw 'unrecognized mouse wheel event: ' + event.type;
}
return delta;
},
mouseX: 0,
mouseY: 0,
mouseMovementX: 0,
mouseMovementY: 0,
touches: {},
lastTouches: {},
calculateMouseEvent: function(event) { // event should be mousemove, mousedown or mouseup
if (Browser.pointerLock) {
// When the pointer is locked, calculate the coordinates
// based on the movement of the mouse.
// Workaround for Firefox bug 764498
if (event.type != 'mousemove' &&
('mozMovementX' in event)) {
Browser.mouseMovementX = Browser.mouseMovementY = 0;
} else {
Browser.mouseMovementX = Browser.getMovementX(event);
Browser.mouseMovementY = Browser.getMovementY(event);
}
// check if SDL is available
if (typeof SDL != "undefined") {
Browser.mouseX = SDL.mouseX + Browser.mouseMovementX;
Browser.mouseY = SDL.mouseY + Browser.mouseMovementY;
} else {
// just add the mouse delta to the current absolut mouse position
// FIXME: ideally this should be clamped against the canvas size and zero
Browser.mouseX += Browser.mouseMovementX;
Browser.mouseY += Browser.mouseMovementY;
}
} else {
// Otherwise, calculate the movement based on the changes
// in the coordinates.
var rect = Module["canvas"].getBoundingClientRect();
var cw = Module["canvas"].width;
var ch = Module["canvas"].height;
// Neither .scrollX or .pageXOffset are defined in a spec, but
// we prefer .scrollX because it is currently in a spec draft.
// (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/)
var scrollX = ((typeof window.scrollX !== 'undefined') ? window.scrollX : window.pageXOffset);
var scrollY = ((typeof window.scrollY !== 'undefined') ? window.scrollY : window.pageYOffset);
#if ASSERTIONS
// If this assert lands, it's likely because the browser doesn't support scrollX or pageXOffset
// and we have no viable fallback.
assert((typeof scrollX !== 'undefined') && (typeof scrollY !== 'undefined'), 'Unable to retrieve scroll position, mouse positions likely broken.');
#endif
if (event.type === 'touchstart' || event.type === 'touchend' || event.type === 'touchmove') {
var touch = event.touch;
if (touch === undefined) {
return; // the "touch" property is only defined in SDL
}
var adjustedX = touch.pageX - (scrollX + rect.left);
var adjustedY = touch.pageY - (scrollY + rect.top);
adjustedX = adjustedX * (cw / rect.width);
adjustedY = adjustedY * (ch / rect.height);
var coords = { x: adjustedX, y: adjustedY };
if (event.type === 'touchstart') {
Browser.lastTouches[touch.identifier] = coords;
Browser.touches[touch.identifier] = coords;
} else if (event.type === 'touchend' || event.type === 'touchmove') {
var last = Browser.touches[touch.identifier];
if (!last) last = coords;
Browser.lastTouches[touch.identifier] = last;
Browser.touches[touch.identifier] = coords;
}
return;
}
var x = event.pageX - (scrollX + rect.left);
var y = event.pageY - (scrollY + rect.top);
// the canvas might be CSS-scaled compared to its backbuffer;
// SDL-using content will want mouse coordinates in terms
// of backbuffer units.
x = x * (cw / rect.width);
y = y * (ch / rect.height);
Browser.mouseMovementX = x - Browser.mouseX;
Browser.mouseMovementY = y - Browser.mouseY;
Browser.mouseX = x;
Browser.mouseY = y;
}
},
asyncLoad: function(url, onload, onerror, noRunDep) {
var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : '';
Module['readAsync'](url, function(arrayBuffer) {
assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).');
onload(new Uint8Array(arrayBuffer));
if (dep) removeRunDependency(dep);
}, function(event) {
if (onerror) {
onerror();
} else {
throw 'Loading data file "' + url + '" failed.';
}
});
if (dep) addRunDependency(dep);
},
resizeListeners: [],
updateResizeListeners: function() {
var canvas = Module['canvas'];
Browser.resizeListeners.forEach(function(listener) {
listener(canvas.width, canvas.height);
});
},
setCanvasSize: function(width, height, noUpdates) {
var canvas = Module['canvas'];
Browser.updateCanvasDimensions(canvas, width, height);
if (!noUpdates) Browser.updateResizeListeners();
},
windowedWidth: 0,
windowedHeight: 0,
setFullscreenCanvasSize: function() {
// check if SDL is available
if (typeof SDL != "undefined") {
var flags = {{{ makeGetValue('SDL.screen', '0', 'i32', 0, 1) }}};
flags = flags | 0x00800000; // set SDL_FULLSCREEN flag
{{{ makeSetValue('SDL.screen', '0', 'flags', 'i32') }}}
}
Browser.updateCanvasDimensions(Module['canvas']);
Browser.updateResizeListeners();
},
setWindowedCanvasSize: function() {
// check if SDL is available
if (typeof SDL != "undefined") {
var flags = {{{ makeGetValue('SDL.screen', '0', 'i32', 0, 1) }}};
flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag
{{{ makeSetValue('SDL.screen', '0', 'flags', 'i32') }}}
}
Browser.updateCanvasDimensions(Module['canvas']);
Browser.updateResizeListeners();
},
updateCanvasDimensions : function(canvas, wNative, hNative) {
if (wNative && hNative) {
canvas.widthNative = wNative;
canvas.heightNative = hNative;
} else {
wNative = canvas.widthNative;
hNative = canvas.heightNative;
}
var w = wNative;
var h = hNative;
if (Module['forcedAspectRatio'] && Module['forcedAspectRatio'] > 0) {
if (w/h < Module['forcedAspectRatio']) {
w = Math.round(h * Module['forcedAspectRatio']);
} else {
h = Math.round(w / Module['forcedAspectRatio']);
}
}
if (((document['fullscreenElement'] || document['mozFullScreenElement'] ||
document['msFullscreenElement'] || document['webkitFullscreenElement'] ||
document['webkitCurrentFullScreenElement']) === canvas.parentNode) && (typeof screen != 'undefined')) {
var factor = Math.min(screen.width / w, screen.height / h);
w = Math.round(w * factor);
h = Math.round(h * factor);
}
if (Browser.resizeCanvas) {
if (canvas.width != w) canvas.width = w;
if (canvas.height != h) canvas.height = h;
if (typeof canvas.style != 'undefined') {
canvas.style.removeProperty( "width");
canvas.style.removeProperty("height");
}
} else {
if (canvas.width != wNative) canvas.width = wNative;
if (canvas.height != hNative) canvas.height = hNative;
if (typeof canvas.style != 'undefined') {
if (w != wNative || h != hNative) {
canvas.style.setProperty( "width", w + "px", "important");
canvas.style.setProperty("height", h + "px", "important");
} else {
canvas.style.removeProperty( "width");
canvas.style.removeProperty("height");
}
}
}
},
wgetRequests: {},
nextWgetRequestHandle: 0,
getNextWgetRequestHandle: function() {
var handle = Browser.nextWgetRequestHandle;
Browser.nextWgetRequestHandle++;
return handle;
}
},
emscripten_async_wget__deps: ['$PATH'],
emscripten_async_wget__proxy: 'sync',
emscripten_async_wget__sig: 'viiii',
emscripten_async_wget: function(url, file, onload, onerror) {
Module['noExitRuntime'] = true;
var _url = Pointer_stringify(url);
var _file = Pointer_stringify(file);
_file = PATH.resolve(FS.cwd(), _file);
function doCallback(callback) {
if (callback) {
var stack = stackSave();
Module['dynCall_vi'](callback, allocate(intArrayFromString(_file), 'i8', ALLOC_STACK));
stackRestore(stack);
}
}
var destinationDirectory = PATH.dirname(_file);
FS.createPreloadedFile(
destinationDirectory,
PATH.basename(_file),
_url, true, true,
function() {
doCallback(onload);
},
function() {
doCallback(onerror);
},
false, // dontCreateFile
false, // canOwn
function() { // preFinish
// if a file exists there, we overwrite it
try {
FS.unlink(_file);
} catch (e) {}
// if the destination directory does not yet exist, create it
FS.mkdirTree(destinationDirectory);
}
);
},
emscripten_async_wget_data__proxy: 'sync',
emscripten_async_wget_data__sig: 'viiii',
emscripten_async_wget_data: function(url, arg, onload, onerror) {
Browser.asyncLoad(Pointer_stringify(url), function(byteArray) {
var buffer = _malloc(byteArray.length);
HEAPU8.set(byteArray, buffer);
Module['dynCall_viii'](onload, arg, buffer, byteArray.length);
_free(buffer);
}, function() {
if (onerror) Module['dynCall_vi'](onerror, arg);
}, true /* no need for run dependency, this is async but will not do any prepare etc. step */ );
},
emscripten_async_wget2__proxy: 'sync',
emscripten_async_wget2__sig: 'iiiiiiiii',
emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) {
Module['noExitRuntime'] = true;
var _url = Pointer_stringify(url);
var _file = Pointer_stringify(file);
_file = PATH.resolve(FS.cwd(), _file);
var _request = Pointer_stringify(request);
var _param = Pointer_stringify(param);
var index = _file.lastIndexOf('/');
var http = new XMLHttpRequest();
http.open(_request, _url, true);
http.responseType = 'arraybuffer';
var handle = Browser.getNextWgetRequestHandle();
var destinationDirectory = PATH.dirname(_file);
// LOAD
http.onload = function http_onload(e) {
if (http.status == 200) {
// if a file exists there, we overwrite it
try {
FS.unlink(_file);
} catch (e) {}
// if the destination directory does not yet exist, create it
FS.mkdirTree(destinationDirectory);
FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(http.response), true, true, false);
if (onload) {
var stack = stackSave();
Module['dynCall_viii'](onload, handle, arg, allocate(intArrayFromString(_file), 'i8', ALLOC_STACK));
stackRestore(stack);
}
} else {
if (onerror) Module['dynCall_viii'](onerror, handle, arg, http.status);
}
delete Browser.wgetRequests[handle];
};
// ERROR
http.onerror = function http_onerror(e) {
if (onerror) Module['dynCall_viii'](onerror, handle, arg, http.status);
delete Browser.wgetRequests[handle];
};
// PROGRESS
http.onprogress = function http_onprogress(e) {
if (e.lengthComputable || (e.lengthComputable === undefined && e.total != 0)) {
var percentComplete = (e.loaded / e.total)*100;
if (onprogress) Module['dynCall_viii'](onprogress, handle, arg, percentComplete);
}
};
// ABORT
http.onabort = function http_onabort(e) {
delete Browser.wgetRequests[handle];
};
if (_request == "POST") {
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.send(_param);
} else {
http.send(null);
}
Browser.wgetRequests[handle] = http;
return handle;
},
emscripten_async_wget2_data__proxy: 'sync',
emscripten_async_wget2_data__sig: 'iiiiiiiii',
emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) {
var _url = Pointer_stringify(url);
var _request = Pointer_stringify(request);
var _param = Pointer_stringify(param);
var http = new XMLHttpRequest();
http.open(_request, _url, true);
http.responseType = 'arraybuffer';
var handle = Browser.getNextWgetRequestHandle();
// LOAD
http.onload = function http_onload(e) {
if (http.status == 200 || _url.substr(0,4).toLowerCase() != "http") {
var byteArray = new Uint8Array(http.response);
var buffer = _malloc(byteArray.length);
HEAPU8.set(byteArray, buffer);
if (onload) Module['dynCall_viiii'](onload, handle, arg, buffer, byteArray.length);
if (free) _free(buffer);
} else {
if (onerror) Module['dynCall_viiii'](onerror, handle, arg, http.status, http.statusText);
}
delete Browser.wgetRequests[handle];
};
// ERROR
http.onerror = function http_onerror(e) {
if (onerror) {
Module['dynCall_viiii'](onerror, handle, arg, http.status, http.statusText);
}
delete Browser.wgetRequests[handle];
};
// PROGRESS
http.onprogress = function http_onprogress(e) {
if (onprogress) Module['dynCall_viiii'](onprogress, handle, arg, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0);
};
// ABORT
http.onabort = function http_onabort(e) {
delete Browser.wgetRequests[handle];
};
if (_request == "POST") {
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.send(_param);
} else {
http.send(null);
}
Browser.wgetRequests[handle] = http;
return handle;
},
emscripten_async_wget2_abort__proxy: 'sync',
emscripten_async_wget2_abort__sig: 'vi',
emscripten_async_wget2_abort: function(handle) {
var http = Browser.wgetRequests[handle];
if (http) {
http.abort();
}
},
emscripten_run_preload_plugins__deps: ['$PATH'],
emscripten_run_preload_plugins__proxy: 'sync',
emscripten_run_preload_plugins__sig: 'iiii',
emscripten_run_preload_plugins: function(file, onload, onerror) {
Module['noExitRuntime'] = true;
var _file = Pointer_stringify(file);
var data = FS.analyzePath(_file);
if (!data.exists) return -1;
FS.createPreloadedFile(
PATH.dirname(_file),
PATH.basename(_file),
new Uint8Array(data.object.contents), true, true,
function() {
if (onload) Module['dynCall_vi'](onload, file);
},
function() {
if (onerror) Module['dynCall_vi'](onerror, file);
},
true // don'tCreateFile - it's already there
);
return 0;
},
emscripten_run_preload_plugins_data__proxy: 'sync',
emscripten_run_preload_plugins_data__sig: 'viiiiii',
emscripten_run_preload_plugins_data: function(data, size, suffix, arg, onload, onerror) {
Module['noExitRuntime'] = true;
var _suffix = Pointer_stringify(suffix);
if (!Browser.asyncPrepareDataCounter) Browser.asyncPrepareDataCounter = 0;
var name = 'prepare_data_' + (Browser.asyncPrepareDataCounter++) + '.' + _suffix;
var lengthAsUTF8 = lengthBytesUTF8(name);
var cname = _malloc(lengthAsUTF8+1);
stringToUTF8(name, cname, lengthAsUTF8+1);
FS.createPreloadedFile(
'/',
name,
{{{ makeHEAPView('U8', 'data', 'data + size') }}},
true, true,
function() {
if (onload) Module['dynCall_vii'](onload, arg, cname);
},
function() {
if (onerror) Module['dynCall_vi'](onerror, arg);
},
true // don'tCreateFile - it's already there
);
},
// Callable from pthread, executes in pthread context.
emscripten_async_run_script__deps: ['emscripten_run_script'],
emscripten_async_run_script: function(script, millis) {
Module['noExitRuntime'] = true;
// TODO: cache these to avoid generating garbage
Browser.safeSetTimeout(function() {
_emscripten_run_script(script);
}, millis);
},
// TODO: currently not callable from a pthread, but immediately calls onerror() if not on main thread.
emscripten_async_load_script: function(url, onload, onerror) {
onload = getFuncWrapper(onload, 'v');
onerror = getFuncWrapper(onerror, 'v');
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) {
console.error('emscripten_async_load_script("' + Pointer_stringify(url) + '") failed, emscripten_async_load_script is currently not available in pthreads!');
return onerror ? onerror() : undefined;
}
#endif
Module['noExitRuntime'] = true;
assert(runDependencies === 0, 'async_load_script must be run when no other dependencies are active');
var script = document.createElement('script');
if (onload) {
script.onload = function script_onload() {
if (runDependencies > 0) {
dependenciesFulfilled = onload;
} else {
onload();
}
};
}
if (onerror) script.onerror = onerror;
script.src = Pointer_stringify(url);
document.body.appendChild(script);
},
// Runs natively in pthread, no __proxy needed.
emscripten_get_main_loop_timing: function(mode, value) {
if (mode) {{{ makeSetValue('mode', 0, 'Browser.mainLoop.timingMode', 'i32') }}};
if (value) {{{ makeSetValue('value', 0, 'Browser.mainLoop.timingValue', 'i32') }}};
},
// Runs natively in pthread, no __proxy needed.
emscripten_set_main_loop_timing: function(mode, value) {
Browser.mainLoop.timingMode = mode;
Browser.mainLoop.timingValue = value;
if (!Browser.mainLoop.func) {
#if ASSERTIONS
console.error('emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up.');
#endif
return 1; // Return non-zero on failure, can't set timing mode when there is no main loop.
}
if (mode == 0 /*EM_TIMING_SETTIMEOUT*/) {
Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setTimeout() {
var timeUntilNextTick = Math.max(0, Browser.mainLoop.tickStartTime + value - _emscripten_get_now())|0;
setTimeout(Browser.mainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop
};
Browser.mainLoop.method = 'timeout';
} else if (mode == 1 /*EM_TIMING_RAF*/) {
Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_rAF() {
Browser.requestAnimationFrame(Browser.mainLoop.runner);
};
Browser.mainLoop.method = 'rAF';
} else if (mode == 2 /*EM_TIMING_SETIMMEDIATE*/) {
if (typeof setImmediate === 'undefined') {
// Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed)
var setImmediates = [];
var emscriptenMainLoopMessageId = 'setimmediate';
function Browser_setImmediate_messageHandler(event) {
// When called in current thread or Worker, the main loop ID is structured slightly different to accommodate for --proxy-to-worker runtime listening to Worker events,
// so check for both cases.
if (event.data === emscriptenMainLoopMessageId || event.data.target === emscriptenMainLoopMessageId) {
event.stopPropagation();
setImmediates.shift()();
}
}
addEventListener("message", Browser_setImmediate_messageHandler, true);
setImmediate = function Browser_emulated_setImmediate(func) {
setImmediates.push(func);
if (ENVIRONMENT_IS_WORKER) {
if (Module['setImmediates'] === undefined) Module['setImmediates'] = [];
Module['setImmediates'].push(func);
postMessage({target: emscriptenMainLoopMessageId}); // In --proxy-to-worker, route the message via proxyClient.js
} else postMessage(emscriptenMainLoopMessageId, "*"); // On the main thread, can just send the message to itself.
}
}
Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setImmediate() {
setImmediate(Browser.mainLoop.runner);
};
Browser.mainLoop.method = 'immediate';
}
return 0;
},
// Runs natively in pthread, no __proxy needed.
emscripten_set_main_loop__deps: ['emscripten_set_main_loop_timing', 'emscripten_get_now'],
emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop, arg, noSetTiming) {
Module['noExitRuntime'] = true;
assert(!Browser.mainLoop.func, 'emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.');
Browser.mainLoop.func = func;
Browser.mainLoop.arg = arg;
var browserIterationFunc;
if (typeof arg !== 'undefined') {
browserIterationFunc = function() {
Module['dynCall_vi'](func, arg);
};
} else {
browserIterationFunc = function() {
Module['dynCall_v'](func);
};
}
var thisMainLoopId = Browser.mainLoop.currentlyRunningMainloop;
Browser.mainLoop.runner = function Browser_mainLoop_runner() {
if (ABORT) return;
if (Browser.mainLoop.queue.length > 0) {
var start = Date.now();
var blocker = Browser.mainLoop.queue.shift();
blocker.func(blocker.arg);
if (Browser.mainLoop.remainingBlockers) {
var remaining = Browser.mainLoop.remainingBlockers;
var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining);
if (blocker.counted) {
Browser.mainLoop.remainingBlockers = next;
} else {
// not counted, but move the progress along a tiny bit
next = next + 0.5; // do not steal all the next one's progress
Browser.mainLoop.remainingBlockers = (8*remaining + next)/9;
}
}
console.log('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers);
Browser.mainLoop.updateStatus();
// catches pause/resume main loop from blocker execution
if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) return;
setTimeout(Browser.mainLoop.runner, 0);
return;
}
// catch pauses from non-main loop sources
if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) return;
// Implement very basic swap interval control
Browser.mainLoop.currentFrameNumber = Browser.mainLoop.currentFrameNumber + 1 | 0;
if (Browser.mainLoop.timingMode == 1/*EM_TIMING_RAF*/ && Browser.mainLoop.timingValue > 1 && Browser.mainLoop.currentFrameNumber % Browser.mainLoop.timingValue != 0) {
// Not the scheduled time to render this frame - skip.
Browser.mainLoop.scheduler();
return;
} else if (Browser.mainLoop.timingMode == 0/*EM_TIMING_SETTIMEOUT*/) {
Browser.mainLoop.tickStartTime = _emscripten_get_now();
}
// Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize
// VBO double-buffering and reduce GPU stalls.
#if USES_GL_EMULATION
GL.newRenderingFrameStarted();
#endif
#if OFFSCREENCANVAS_SUPPORT
// If the current GL context is an OffscreenCanvas, but it was initialized with implicit swap mode, perform the swap
// in behalf of the user.
if (typeof GL !== 'undefined' && GL.currentContext && !GL.currentContext.attributes.explicitSwapControl && GL.currentContext.GLctx.commit) {
GL.currentContext.GLctx.commit();
}
#endif
if (Browser.mainLoop.method === 'timeout' && Module.ctx) {
Module.printErr('Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!');
Browser.mainLoop.method = ''; // just warn once per call to set main loop
}
Browser.mainLoop.runIter(browserIterationFunc);
#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
// catch pauses from the main loop itself
if (thisMainLoopId < Browser.mainLoop.currentlyRunningMainloop) return;
// Queue new audio data. This is important to be right after the main loop invocation, so that we will immediately be able
// to queue the newest produced audio samples.
// TODO: Consider adding pre- and post- rAF callbacks so that GL.newRenderingFrameStarted() and SDL.audio.queueNewAudioData()
// do not need to be hardcoded into this function, but can be more generic.
if (typeof SDL === 'object' && SDL.audio && SDL.audio.queueNewAudioData) SDL.audio.queueNewAudioData();
Browser.mainLoop.scheduler();
}
if (!noSetTiming) {
if (fps && fps > 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 1000.0 / fps);
else _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, 1); // Do rAF by rendering each frame (no decimating)
Browser.mainLoop.scheduler();
}
if (simulateInfiniteLoop) {
throw 'SimulateInfiniteLoop';
}
},
// Runs natively in pthread, no __proxy needed.
emscripten_set_main_loop_arg__deps: ['emscripten_set_main_loop'],
emscripten_set_main_loop_arg: function(func, arg, fps, simulateInfiniteLoop) {
_emscripten_set_main_loop(func, fps, simulateInfiniteLoop, arg);
},
// Runs natively in pthread, no __proxy needed.
emscripten_cancel_main_loop: function() {
Browser.mainLoop.pause();
Browser.mainLoop.func = null;
},
// Runs natively in pthread, no __proxy needed.
emscripten_pause_main_loop: function() {
Browser.mainLoop.pause();
},
// Runs natively in pthread, no __proxy needed.
emscripten_resume_main_loop: function() {
Browser.mainLoop.resume();
},
// Runs natively in pthread, no __proxy needed.
_emscripten_push_main_loop_blocker: function(func, arg, name) {
Browser.mainLoop.queue.push({ func: function() {
Module['dynCall_vi'](func, arg);
}, name: Pointer_stringify(name), counted: true });
Browser.mainLoop.updateStatus();
},
// Runs natively in pthread, no __proxy needed.
_emscripten_push_uncounted_main_loop_blocker: function(func, arg, name) {
Browser.mainLoop.queue.push({ func: function() {
Module['dynCall_vi'](func, arg);
}, name: Pointer_stringify(name), counted: false });
Browser.mainLoop.updateStatus();
},
// Runs natively in pthread, no __proxy needed.
emscripten_set_main_loop_expected_blockers: function(num) {
Browser.mainLoop.expectedBlockers = num;
Browser.mainLoop.remainingBlockers = num;
Browser.mainLoop.updateStatus();
},
// Runs natively in pthread, no __proxy needed.
emscripten_async_call: function(func, arg, millis) {
Module['noExitRuntime'] = true;
function wrapper() {
getFuncWrapper(func, 'vi')(arg);
}
if (millis >= 0) {
Browser.safeSetTimeout(wrapper, millis);
} else {
Browser.safeRequestAnimationFrame(wrapper);
}
},
// Callable in pthread without __proxy needed.
emscripten_exit_with_live_runtime: function() {
Module['noExitRuntime'] = true;
throw 'SimulateInfiniteLoop';
},
emscripten_force_exit__proxy: 'sync',
emscripten_force_exit__sig: 'vi',
emscripten_force_exit: function(status) {
#if NO_EXIT_RUNTIME
#if ASSERTIONS
warnOnce('emscripten_force_exit cannot actually shut down the runtime, as the build has NO_EXIT_RUNTIME set');
#endif
#endif
Module['noExitRuntime'] = false;
Module['exit'](status);
},
emscripten_get_device_pixel_ratio__proxy: 'sync',
emscripten_get_device_pixel_ratio__sig: 'd',
emscripten_get_device_pixel_ratio: function() {
return window.devicePixelRatio || 1.0;
},
emscripten_hide_mouse__proxy: 'sync',
emscripten_hide_mouse__sig: 'v',
emscripten_hide_mouse: function() {
var styleSheet = document.styleSheets[0];
var rules = styleSheet.cssRules;
for (var i = 0; i < rules.length; i++) {
if (rules[i].cssText.substr(0, 6) == 'canvas') {
styleSheet.deleteRule(i);
i--;
}
}
styleSheet.insertRule('canvas.emscripten { border: 1px solid black; cursor: none; }', 0);
},
emscripten_set_canvas_size__proxy: 'sync',
emscripten_set_canvas_size__sig: 'vii',
emscripten_set_canvas_size: function(width, height) {
Browser.setCanvasSize(width, height);
},
emscripten_get_canvas_size__proxy: 'sync',
emscripten_get_canvas_size__sig: 'viii',
emscripten_get_canvas_size: function(width, height, isFullscreen) {
var canvas = Module['canvas'];
{{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}};
{{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}};
{{{ makeSetValue('isFullscreen', '0', 'Browser.isFullscreen ? 1 : 0', 'i32') }}};
},
// To avoid creating worker parent->child chains, always proxies to execute on the main thread.
emscripten_create_worker__proxy: 'sync',
emscripten_create_worker__sig: 'ii',
emscripten_create_worker: function(url) {
url = Pointer_stringify(url);
var id = Browser.workers.length;
var info = {
worker: new Worker(url),
callbacks: [],
awaited: 0,
buffer: 0,
bufferSize: 0
};
info.worker.onmessage = function info_worker_onmessage(msg) {
if (ABORT) return;
var info = Browser.workers[id];
if (!info) return; // worker was destroyed meanwhile
var callbackId = msg.data['callbackId'];
var callbackInfo = info.callbacks[callbackId];
if (!callbackInfo) return; // no callback or callback removed meanwhile
// Don't trash our callback state if we expect additional calls.
if (msg.data['finalResponse']) {
info.awaited--;
info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this
}
var data = msg.data['data'];
if (data) {
if (!data.byteLength) data = new Uint8Array(data);
if (!info.buffer || info.bufferSize < data.length) {
if (info.buffer) _free(info.buffer);
info.bufferSize = data.length;
info.buffer = _malloc(data.length);
}
HEAPU8.set(data, info.buffer);
callbackInfo.func(info.buffer, data.length, callbackInfo.arg);
} else {
callbackInfo.func(0, 0, callbackInfo.arg);
}
};
Browser.workers.push(info);
return id;
},
emscripten_destroy_worker__proxy: 'sync',
emscripten_destroy_worker__sig: 'vi',
emscripten_destroy_worker: function(id) {
var info = Browser.workers[id];
info.worker.terminate();
if (info.buffer) _free(info.buffer);
Browser.workers[id] = null;
},
emscripten_call_worker__proxy: 'sync',
emscripten_call_worker__sig: 'viiiiii',
emscripten_call_worker: function(id, funcName, data, size, callback, arg) {
Module['noExitRuntime'] = true; // should we only do this if there is a callback?
funcName = Pointer_stringify(funcName);
var info = Browser.workers[id];
var callbackId = -1;
if (callback) {
callbackId = info.callbacks.length;
info.callbacks.push({
func: getFuncWrapper(callback, 'viii'),
arg: arg
});
info.awaited++;
}
var transferObject = {
'funcName': funcName,
'callbackId': callbackId,
'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0
};
if (data) {
info.worker.postMessage(transferObject, [transferObject.data.buffer]);
} else {
info.worker.postMessage(transferObject);
}
},
emscripten_worker_respond_provisionally__proxy: 'sync',
emscripten_worker_respond_provisionally__sig: 'vii',
emscripten_worker_respond_provisionally: function(data, size) {
if (workerResponded) throw 'already responded with final response!';
var transferObject = {
'callbackId': workerCallbackId,
'finalResponse': false,
'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0
};
if (data) {
postMessage(transferObject, [transferObject.data.buffer]);
} else {
postMessage(transferObject);
}
},
emscripten_worker_respond__proxy: 'sync',
emscripten_worker_respond__sig: 'vii',
emscripten_worker_respond: function(data, size) {
if (workerResponded) throw 'already responded with final response!';
workerResponded = true;
var transferObject = {
'callbackId': workerCallbackId,
'finalResponse': true,
'data': data ? new Uint8Array({{{ makeHEAPView('U8', 'data', 'data + size') }}}) : 0
};
if (data) {
postMessage(transferObject, [transferObject.data.buffer]);
} else {
postMessage(transferObject);
}
},
emscripten_get_worker_queue_size__proxy: 'sync',
emscripten_get_worker_queue_size__sig: 'i',
emscripten_get_worker_queue_size: function(id) {
var info = Browser.workers[id];
if (!info) return -1;
return info.awaited;
},
emscripten_get_preloaded_image_data__deps: ['$PATH'],
emscripten_get_preloaded_image_data__proxy: 'sync',
emscripten_get_preloaded_image_data__sig: 'iiii',
emscripten_get_preloaded_image_data: function(path, w, h) {
if (typeof path === "number") {
path = Pointer_stringify(path);
}
path = PATH.resolve(path);
var canvas = Module["preloadedImages"][path];
if (canvas) {
var ctx = canvas.getContext("2d");
var image = ctx.getImageData(0, 0, canvas.width, canvas.height);
var buf = _malloc(canvas.width * canvas.height * 4);
HEAPU8.set(image.data, buf);
{{{ makeSetValue('w', '0', 'canvas.width', 'i32') }}};
{{{ makeSetValue('h', '0', 'canvas.height', 'i32') }}};
return buf;
}
return 0;
},
emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data'],
emscripten_get_preloaded_image_data_from_FILE__proxy: 'sync',
emscripten_get_preloaded_image_data_from_FILE__sig: 'iiii',
emscripten_get_preloaded_image_data_from_FILE: function(file, w, h) {
var fd = Module['_fileno'](file);
var stream = FS.getStream(fd);
if (stream) {
return _emscripten_get_preloaded_image_data(stream.path, w, h);
}
return 0;
}
};
autoAddDeps(LibraryBrowser, '$Browser');
mergeInto(LibraryManager.library, LibraryBrowser);
/* Useful stuff for browser debugging
function slowLog(label, text) {
if (!slowLog.labels) slowLog.labels = {};
if (!slowLog.labels[label]) slowLog.labels[label] = 0;
var now = Date.now();
if (now - slowLog.labels[label] > 1000) {
Module.print(label + ': ' + text);
slowLog.labels[label] = now;
}
}
*/
// === Preamble library stuff ===
// Documentation for the public APIs defined in this file must be updated in:
// site/source/docs/api_reference/preamble.js.rst
// A prebuilt local version of the documentation is available at:
// site/build/text/docs/api_reference/preamble.js.txt
// You can also build docs locally as HTML or other formats in site/
// An online HTML version (which may be of a different version of Emscripten)
// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
#if BENCHMARK
Module.realPrint = Module.print;
Module.print = Module.printErr = function(){};
#endif
#if SAFE_HEAP
function getSafeHeapType(bytes, isFloat) {
switch (bytes) {
case 1: return 'i8';
case 2: return 'i16';
case 4: return isFloat ? 'float' : 'i32';
case 8: return 'double';
default: assert(0);
}
}
#if SAFE_HEAP_LOG
var SAFE_HEAP_COUNTER = 0;
#endif
function SAFE_HEAP_STORE(dest, value, bytes, isFloat) {
#if SAFE_HEAP_LOG
Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat, SAFE_HEAP_COUNTER++]);
#endif
if (dest <= 0) abort('segmentation fault storing ' + bytes + ' bytes to address ' + dest);
if (dest % bytes !== 0) abort('alignment error storing to address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes);
if (staticSealed) {
if (dest + bytes > HEAP32[DYNAMICTOP_PTR>>2]) abort('segmentation fault, exceeded the top of the available dynamic heap when storing ' + bytes + ' bytes to address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + HEAP32[DYNAMICTOP_PTR>>2]);
assert(DYNAMICTOP_PTR);
assert(HEAP32[DYNAMICTOP_PTR>>2] <= TOTAL_MEMORY);
} else {
if (dest + bytes > STATICTOP) abort('segmentation fault, exceeded the top of the available static heap when storing ' + bytes + ' bytes to address ' + dest + '. STATICTOP=' + STATICTOP);
}
setValue(dest, value, getSafeHeapType(bytes, isFloat), 1);
}
function SAFE_HEAP_STORE_D(dest, value, bytes) {
SAFE_HEAP_STORE(dest, value, bytes, true);
}
function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) {
if (dest <= 0) abort('segmentation fault loading ' + bytes + ' bytes from address ' + dest);
if (dest % bytes !== 0) abort('alignment error loading from address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes);
if (staticSealed) {
if (dest + bytes > HEAP32[DYNAMICTOP_PTR>>2]) abort('segmentation fault, exceeded the top of the available dynamic heap when loading ' + bytes + ' bytes from address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + HEAP32[DYNAMICTOP_PTR>>2]);
assert(DYNAMICTOP_PTR);
assert(HEAP32[DYNAMICTOP_PTR>>2] <= TOTAL_MEMORY);
} else {
if (dest + bytes > STATICTOP) abort('segmentation fault, exceeded the top of the available static heap when loading ' + bytes + ' bytes from address ' + dest + '. STATICTOP=' + STATICTOP);
}
var type = getSafeHeapType(bytes, isFloat);
var ret = getValue(dest, type, 1);
if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1);
#if SAFE_HEAP_LOG
Module.print('SAFE_HEAP load: ' + [dest, ret, bytes, isFloat, unsigned, SAFE_HEAP_COUNTER++]);
#endif
return ret;
}
function SAFE_HEAP_LOAD_D(dest, bytes, unsigned) {
return SAFE_HEAP_LOAD(dest, bytes, unsigned, true);
}
function SAFE_FT_MASK(value, mask) {
var ret = value & mask;
if (ret !== value) {
abort('Function table mask error: function pointer is ' + value + ' which is masked by ' + mask + ', the likely cause of this is that the function pointer is being called by the wrong type.');
}
return ret;
}
function segfault() {
abort('segmentation fault');
}
function alignfault() {
abort('alignment fault');
}
function ftfault() {
abort('Function table mask error');
}
#endif
//========================================
// Runtime essentials
//========================================
var ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort()
var EXITSTATUS = 0;
/** @type {function(*, string=)} */
function assert(condition, text) {
if (!condition) {
abort('Assertion failed: ' + text);
}
}
var globalScope = this;
// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
function getCFunc(ident) {
var func = Module['_' + ident]; // closure exported function
assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported');
return func;
}
var JSfuncs = {
// Helpers for cwrap -- it can't refer to Runtime directly because it might
// be renamed by closure, instead it calls JSfuncs['stackSave'].body to find
// out what the minified function name is.
'stackSave': function() {
stackSave()
},
'stackRestore': function() {
stackRestore()
},
// type conversion from js to c
'arrayToC' : function(arr) {
var ret = stackAlloc(arr.length);
writeArrayToMemory(arr, ret);
return ret;
},
'stringToC' : function(str) {
var ret = 0;
if (str !== null && str !== undefined && str !== 0) { // null string
// at most 4 bytes per UTF-8 code point, +1 for the trailing '\0'
var len = (str.length << 2) + 1;
ret = stackAlloc(len);
stringToUTF8(str, ret, len);
}
return ret;
}
};
// For fast lookup of conversion functions
var toC = {
'string': JSfuncs['stringToC'], 'array': JSfuncs['arrayToC']
};
// C calling interface.
function ccall (ident, returnType, argTypes, args, opts) {
var func = getCFunc(ident);
var cArgs = [];
var stack = 0;
#if ASSERTIONS
assert(returnType !== 'array', 'Return type should not be "array".');
#endif
if (args) {
for (var i = 0; i < args.length; i++) {
var converter = toC[argTypes[i]];
if (converter) {
if (stack === 0) stack = stackSave();
cArgs[i] = converter(args[i]);
} else {
cArgs[i] = args[i];
}
}
}
var ret = func.apply(null, cArgs);
#if ASSERTIONS
#if EMTERPRETIFY_ASYNC
if ((!opts || !opts.async) && typeof EmterpreterAsync === 'object') {
assert(!EmterpreterAsync.state, 'cannot start async op with normal JS calling ccall');
}
if (opts && opts.async) assert(!returnType, 'async ccalls cannot return values');
#endif
#endif
if (returnType === 'string') ret = Pointer_stringify(ret);
else if (returnType === 'boolean') ret = Boolean(ret);
if (stack !== 0) {
#if EMTERPRETIFY_ASYNC
if (opts && opts.async) {
EmterpreterAsync.asyncFinalizers.push(function() {
stackRestore(stack);
});
return;
}
#endif
stackRestore(stack);
}
return ret;
}
function cwrap (ident, returnType, argTypes) {
argTypes = argTypes || [];
var cfunc = getCFunc(ident);
// When the function takes numbers and returns a number, we can just return
// the original function
var numericArgs = argTypes.every(function(type){ return type === 'number'});
var numericRet = returnType !== 'string';
if (numericRet && numericArgs) {
return cfunc;
}
return function() {
return ccall(ident, returnType, argTypes, arguments);
}
}
/** @type {function(number, number, string, boolean=)} */
function setValue(ptr, value, type, noSafe) {
type = type || 'i8';
if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
#if SAFE_HEAP
if (noSafe) {
switch(type) {
case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1', undefined, undefined, undefined, '1') }}}; break;
case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8', undefined, undefined, undefined, '1') }}}; break;
case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16', undefined, undefined, undefined, '1') }}}; break;
case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32', undefined, undefined, undefined, '1') }}}; break;
case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64', undefined, undefined, undefined, '1') }}}; break;
case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float', undefined, undefined, undefined, '1') }}}; break;
case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double', undefined, undefined, undefined, '1') }}}; break;
default: abort('invalid type for setValue: ' + type);
}
} else {
#endif
switch(type) {
case 'i1': {{{ makeSetValue('ptr', '0', 'value', 'i1') }}}; break;
case 'i8': {{{ makeSetValue('ptr', '0', 'value', 'i8') }}}; break;
case 'i16': {{{ makeSetValue('ptr', '0', 'value', 'i16') }}}; break;
case 'i32': {{{ makeSetValue('ptr', '0', 'value', 'i32') }}}; break;
case 'i64': {{{ makeSetValue('ptr', '0', 'value', 'i64') }}}; break;
case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break;
case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break;
default: abort('invalid type for setValue: ' + type);
}
#if SAFE_HEAP
}
#endif
}
/** @type {function(number, string, boolean=)} */
function getValue(ptr, type, noSafe) {
type = type || 'i8';
if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
#if SAFE_HEAP
if (noSafe) {
switch(type) {
case 'i1': return {{{ makeGetValue('ptr', '0', 'i1', undefined, undefined, undefined, undefined, '1') }}};
case 'i8': return {{{ makeGetValue('ptr', '0', 'i8', undefined, undefined, undefined, undefined, '1') }}};
case 'i16': return {{{ makeGetValue('ptr', '0', 'i16', undefined, undefined, undefined, undefined, '1') }}};
case 'i32': return {{{ makeGetValue('ptr', '0', 'i32', undefined, undefined, undefined, undefined, '1') }}};
case 'i64': return {{{ makeGetValue('ptr', '0', 'i64', undefined, undefined, undefined, undefined, '1') }}};
case 'float': return {{{ makeGetValue('ptr', '0', 'float', undefined, undefined, undefined, undefined, '1') }}};
case 'double': return {{{ makeGetValue('ptr', '0', 'double', undefined, undefined, undefined, undefined, '1') }}};
default: abort('invalid type for getValue: ' + type);
}
} else {
#endif
switch(type) {
case 'i1': return {{{ makeGetValue('ptr', '0', 'i1') }}};
case 'i8': return {{{ makeGetValue('ptr', '0', 'i8') }}};
case 'i16': return {{{ makeGetValue('ptr', '0', 'i16') }}};
case 'i32': return {{{ makeGetValue('ptr', '0', 'i32') }}};
case 'i64': return {{{ makeGetValue('ptr', '0', 'i64') }}};
case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}};
case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}};
default: abort('invalid type for getValue: ' + type);
}
#if SAFE_HEAP
}
#endif
return null;
}
var ALLOC_NORMAL = 0; // Tries to use _malloc()
var ALLOC_STACK = 1; // Lives for the duration of the current function call
var ALLOC_STATIC = 2; // Cannot be freed
var ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk
var ALLOC_NONE = 4; // Do not allocate
// allocate(): This is for internal use. You can use it yourself as well, but the interface
// is a little tricky (see docs right below). The reason is that it is optimized
// for multiple syntaxes to save space in generated code. So you should
// normally not use allocate(), and instead allocate memory using _malloc(),
// initialize it with setValue(), and so forth.
// @slab: An array of data, or a number. If a number, then the size of the block to allocate,
// in *bytes* (note that this is sometimes confusing: the next parameter does not
// affect this!)
// @types: Either an array of types, one for each byte (or 0 if no type at that position),
// or a single type which is used for the entire block. This only matters if there
// is initial data - if @slab is a number, then this does not matter at all and is
// ignored.
// @allocator: How to allocate memory, see ALLOC_*
/** @type {function((TypedArray|Array<number>|number), string, number, number=)} */
function allocate(slab, types, allocator, ptr) {
var zeroinit, size;
if (typeof slab === 'number') {
zeroinit = true;
size = slab;
} else {
zeroinit = false;
size = slab.length;
}
var singleType = typeof types === 'string' ? types : null;
var ret;
if (allocator == ALLOC_NONE) {
ret = ptr;
} else {
ret = [typeof _malloc === 'function' ? _malloc : staticAlloc, stackAlloc, staticAlloc, dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
}
if (zeroinit) {
var stop;
ptr = ret;
assert((ret & 3) == 0);
stop = ret + (size & ~3);
for (; ptr < stop; ptr += 4) {
{{{ makeSetValue('ptr', '0', '0', 'i32', null, true) }}};
}
stop = ret + size;
while (ptr < stop) {
{{{ makeSetValue('ptr++', '0', '0', 'i8', null, true) }}};
}
return ret;
}
if (singleType === 'i8') {
if (slab.subarray || slab.slice) {
HEAPU8.set(/** @type {!Uint8Array} */ (slab), ret);
} else {
HEAPU8.set(new Uint8Array(slab), ret);
}
return ret;
}
var i = 0, type, typeSize, previousType;
while (i < size) {
var curr = slab[i];
type = singleType || types[i];
if (type === 0) {
i++;
continue;
}
#if ASSERTIONS
assert(type, 'Must know what type to store in allocate!');
#endif
if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
setValue(ret+i, curr, type);
// no need to look up size unless type changes, so cache it
if (previousType !== type) {
typeSize = getNativeTypeSize(type);
previousType = type;
}
i += typeSize;
}
return ret;
}
// Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready
function getMemory(size) {
if (!staticSealed) return staticAlloc(size);
if (!runtimeInitialized) return dynamicAlloc(size);
return _malloc(size);
}
/** @type {function(number, number=)} */
function Pointer_stringify(ptr, length) {
if (length === 0 || !ptr) return '';
// Find the length, and check for UTF while doing so
var hasUtf = 0;
var t;
var i = 0;
while (1) {
#if ASSERTIONS
assert(ptr + i < TOTAL_MEMORY);
#endif
t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}};
hasUtf |= t;
if (t == 0 && !length) break;
i++;
if (length && i == length) break;
}
if (!length) length = i;
var ret = '';
if (hasUtf < 128) {
var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack
var curr;
while (length > 0) {
curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));
ret = ret ? ret + curr : curr;
ptr += MAX_CHUNK;
length -= MAX_CHUNK;
}
return ret;
}
return UTF8ToString(ptr);
}
// Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns
// a copy of that string as a Javascript String object.
function AsciiToString(ptr) {
var str = '';
while (1) {
var ch = {{{ makeGetValue('ptr++', 0, 'i8') }}};
if (!ch) return str;
str += String.fromCharCode(ch);
}
}
// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
// null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP.
function stringToAscii(str, outPtr) {
return writeAsciiToMemory(str, outPtr, false);
}
// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
// a copy of that string as a Javascript String object.
#if TEXTDECODER
var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;
#endif
function UTF8ArrayToString(u8Array, idx) {
#if TEXTDECODER
var endPtr = idx;
// TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
// Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
while (u8Array[endPtr]) ++endPtr;
if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {
return UTF8Decoder.decode(u8Array.subarray(idx, endPtr));
} else {
#endif
var u0, u1, u2, u3, u4, u5;
var str = '';
while (1) {
// For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
u0 = u8Array[idx++];
if (!u0) return str;
if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
u1 = u8Array[idx++] & 63;
if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
u2 = u8Array[idx++] & 63;
if ((u0 & 0xF0) == 0xE0) {
u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
} else {
u3 = u8Array[idx++] & 63;
if ((u0 & 0xF8) == 0xF0) {
u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;
} else {
u4 = u8Array[idx++] & 63;
if ((u0 & 0xFC) == 0xF8) {
u0 = ((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;
} else {
u5 = u8Array[idx++] & 63;
u0 = ((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;
}
}
}
if (u0 < 0x10000) {
str += String.fromCharCode(u0);
} else {
var ch = u0 - 0x10000;
str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
}
}
#if TEXTDECODER
}
#endif
}
// Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns
// a copy of that string as a Javascript String object.
function UTF8ToString(ptr) {
return UTF8ArrayToString({{{ heapAndOffset('HEAPU8', 'ptr') }}});
}
// Copies the given Javascript String object 'str' to the given byte array at address 'outIdx',
// encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP.
// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
// Parameters:
// str: the Javascript string to copy.
// outU8Array: the array to copy to. Each index in this array is assumed to be one 8-byte element.
// outIdx: The starting offset in the array to begin the copying.
// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
// terminator, i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else.
// maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator.
// Returns the number of bytes written, EXCLUDING the null terminator.
function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {
if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes.
return 0;
var startIdx = outIdx;
var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator.
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
// For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629
var u = str.charCodeAt(i); // possibly a lead surrogate
if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
if (u <= 0x7F) {
if (outIdx >= endIdx) break;
outU8Array[outIdx++] = u;
} else if (u <= 0x7FF) {
if (outIdx + 1 >= endIdx) break;
outU8Array[outIdx++] = 0xC0 | (u >> 6);
outU8Array[outIdx++] = 0x80 | (u & 63);
} else if (u <= 0xFFFF) {
if (outIdx + 2 >= endIdx) break;
outU8Array[outIdx++] = 0xE0 | (u >> 12);
outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
outU8Array[outIdx++] = 0x80 | (u & 63);
} else if (u <= 0x1FFFFF) {
if (outIdx + 3 >= endIdx) break;
outU8Array[outIdx++] = 0xF0 | (u >> 18);
outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
outU8Array[outIdx++] = 0x80 | (u & 63);
} else if (u <= 0x3FFFFFF) {
if (outIdx + 4 >= endIdx) break;
outU8Array[outIdx++] = 0xF8 | (u >> 24);
outU8Array[outIdx++] = 0x80 | ((u >> 18) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
outU8Array[outIdx++] = 0x80 | (u & 63);
} else {
if (outIdx + 5 >= endIdx) break;
outU8Array[outIdx++] = 0xFC | (u >> 30);
outU8Array[outIdx++] = 0x80 | ((u >> 24) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 18) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);
outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
outU8Array[outIdx++] = 0x80 | (u & 63);
}
}
// Null-terminate the pointer to the buffer.
outU8Array[outIdx] = 0;
return outIdx - startIdx;
}
// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
// null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP.
// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
// Returns the number of bytes written, EXCLUDING the null terminator.
function stringToUTF8(str, outPtr, maxBytesToWrite) {
#if ASSERTIONS
assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
#endif
return stringToUTF8Array(str, {{{ heapAndOffset('HEAPU8', 'outPtr') }}}, maxBytesToWrite);
}
// Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte.
function lengthBytesUTF8(str) {
var len = 0;
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.
// See http://unicode.org/faq/utf_bom.html#utf16-3
var u = str.charCodeAt(i); // possibly a lead surrogate
if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
if (u <= 0x7F) {
++len;
} else if (u <= 0x7FF) {
len += 2;
} else if (u <= 0xFFFF) {
len += 3;
} else if (u <= 0x1FFFFF) {
len += 4;
} else if (u <= 0x3FFFFFF) {
len += 5;
} else {
len += 6;
}
}
return len;
}
// Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
// a copy of that string as a Javascript String object.
var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;
function UTF16ToString(ptr) {
#if ASSERTIONS
assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!');
#endif
#if TEXTDECODER
var endPtr = ptr;
// TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
// Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
var idx = endPtr >> 1;
while (HEAP16[idx]) ++idx;
endPtr = idx << 1;
if (endPtr - ptr > 32 && UTF16Decoder) {
return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));
} else {
#endif
var i = 0;
var str = '';
while (1) {
var codeUnit = {{{ makeGetValue('ptr', 'i*2', 'i16') }}};
if (codeUnit == 0) return str;
++i;
// fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
str += String.fromCharCode(codeUnit);
}
#if TEXTDECODER
}
#endif
}
// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
// null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP.
// Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write.
// Parameters:
// str: the Javascript string to copy.
// outPtr: Byte address in Emscripten HEAP where to write the string to.
// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
// terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else.
// maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator.
// Returns the number of bytes written, EXCLUDING the null terminator.
function stringToUTF16(str, outPtr, maxBytesToWrite) {
#if ASSERTIONS
assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!');
#endif
#if ASSERTIONS
assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
#endif
// Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
if (maxBytesToWrite === undefined) {
maxBytesToWrite = 0x7FFFFFFF;
}
if (maxBytesToWrite < 2) return 0;
maxBytesToWrite -= 2; // Null terminator.
var startPtr = outPtr;
var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length;
for (var i = 0; i < numCharsToWrite; ++i) {
// charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
{{{ makeSetValue('outPtr', 0, 'codeUnit', 'i16') }}};
outPtr += 2;
}
// Null-terminate the pointer to the HEAP.
{{{ makeSetValue('outPtr', 0, 0, 'i16') }}};
return outPtr - startPtr;
}
// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
function lengthBytesUTF16(str) {
return str.length*2;
}
function UTF32ToString(ptr) {
#if ASSERTIONS
assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!');
#endif
var i = 0;
var str = '';
while (1) {
var utf32 = {{{ makeGetValue('ptr', 'i*4', 'i32') }}};
if (utf32 == 0)
return str;
++i;
// Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.
// See http://unicode.org/faq/utf_bom.html#utf16-3
if (utf32 >= 0x10000) {
var ch = utf32 - 0x10000;
str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
} else {
str += String.fromCharCode(utf32);
}
}
}
// Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
// null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP.
// Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write.
// Parameters:
// str: the Javascript string to copy.
// outPtr: Byte address in Emscripten HEAP where to write the string to.
// maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
// terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else.
// maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator.
// Returns the number of bytes written, EXCLUDING the null terminator.
function stringToUTF32(str, outPtr, maxBytesToWrite) {
#if ASSERTIONS
assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!');
#endif
#if ASSERTIONS
assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
#endif
// Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
if (maxBytesToWrite === undefined) {
maxBytesToWrite = 0x7FFFFFFF;
}
if (maxBytesToWrite < 4) return 0;
var startPtr = outPtr;
var endPtr = startPtr + maxBytesToWrite - 4;
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
// See http://unicode.org/faq/utf_bom.html#utf16-3
var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
var trailSurrogate = str.charCodeAt(++i);
codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
}
{{{ makeSetValue('outPtr', 0, 'codeUnit', 'i32') }}};
outPtr += 4;
if (outPtr + 4 > endPtr) break;
}
// Null-terminate the pointer to the HEAP.
{{{ makeSetValue('outPtr', 0, 0, 'i32') }}};
return outPtr - startPtr;
}
// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
function lengthBytesUTF32(str) {
var len = 0;
for (var i = 0; i < str.length; ++i) {
// Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.
// See http://unicode.org/faq/utf_bom.html#utf16-3
var codeUnit = str.charCodeAt(i);
if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate.
len += 4;
}
return len;
}
// Allocate heap space for a JS string, and write it there.
// It is the responsibility of the caller to free() that memory.
function allocateUTF8(str) {
var size = lengthBytesUTF8(str) + 1;
var ret = _malloc(size);
if (ret) stringToUTF8Array(str, HEAP8, ret, size);
return ret;
}
// Allocate stack space for a JS string, and write it there.
function allocateUTF8OnStack(str) {
var size = lengthBytesUTF8(str) + 1;
var ret = stackAlloc(size);
stringToUTF8Array(str, HEAP8, ret, size);
return ret;
}
function demangle(func) {
#if DEMANGLE_SUPPORT
var __cxa_demangle_func = Module['___cxa_demangle'] || Module['__cxa_demangle'];
assert(__cxa_demangle_func);
try {
var s =
#if WASM_BACKEND
func;
#else
func.substr(1);
#endif
var len = lengthBytesUTF8(s)+1;
var buf = _malloc(len);
stringToUTF8(s, buf, len);
var status = _malloc(4);
var ret = __cxa_demangle_func(buf, 0, 0, status);
if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) {
return Pointer_stringify(ret);
}
// otherwise, libcxxabi failed
} catch(e) {
// ignore problems here
} finally {
if (buf) _free(buf);
if (status) _free(status);
if (ret) _free(ret);
}
// failure when using libcxxabi, don't demangle
return func;
#else // DEMANGLE_SUPPORT
#if ASSERTIONS
warnOnce('warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling');
#endif // ASSERTIONS
return func;
#endif // DEMANGLE_SUPPORT
}
function demangleAll(text) {
var regex =
#if WASM_BACKEND
/_Z[\w\d_]+/g;
#else
/__Z[\w\d_]+/g;
#endif
return text.replace(regex,
function(x) {
var y = demangle(x);
return x === y ? x : (x + ' [' + y + ']');
});
}
function jsStackTrace() {
var err = new Error();
if (!err.stack) {
// IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown,
// so try that as a special-case.
try {
throw new Error(0);
} catch(e) {
err = e;
}
if (!err.stack) {
return '(no stack trace available)';
}
}
return err.stack.toString();
}
function stackTrace() {
var js = jsStackTrace();
if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
return demangleAll(js);
}
// Memory management
var PAGE_SIZE = 16384;
var WASM_PAGE_SIZE = 65536;
var ASMJS_PAGE_SIZE = 16777216;
var MIN_TOTAL_MEMORY = 16777216;
function alignUp(x, multiple) {
if (x % multiple > 0) {
x += multiple - (x % multiple);
}
return x;
}
var HEAP,
/** @type {ArrayBuffer} */
buffer,
/** @type {Int8Array} */
HEAP8,
/** @type {Uint8Array} */
HEAPU8,
/** @type {Int16Array} */
HEAP16,
/** @type {Uint16Array} */
HEAPU16,
/** @type {Int32Array} */
HEAP32,
/** @type {Uint32Array} */
HEAPU32,
/** @type {Float32Array} */
HEAPF32,
/** @type {Float64Array} */
HEAPF64;
function updateGlobalBuffer(buf) {
Module['buffer'] = buffer = buf;
}
function updateGlobalBufferViews() {
Module['HEAP8'] = HEAP8 = new Int8Array(buffer);
Module['HEAP16'] = HEAP16 = new Int16Array(buffer);
Module['HEAP32'] = HEAP32 = new Int32Array(buffer);
Module['HEAPU8'] = HEAPU8 = new Uint8Array(buffer);
Module['HEAPU16'] = HEAPU16 = new Uint16Array(buffer);
Module['HEAPU32'] = HEAPU32 = new Uint32Array(buffer);
Module['HEAPF32'] = HEAPF32 = new Float32Array(buffer);
Module['HEAPF64'] = HEAPF64 = new Float64Array(buffer);
}
var STATIC_BASE, STATICTOP, staticSealed; // static area
var STACK_BASE, STACKTOP, STACK_MAX; // stack area
var DYNAMIC_BASE, DYNAMICTOP_PTR; // dynamic area handled by sbrk
#if USE_PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) { // Pthreads have already initialized these variables in src/pthread-main.js, where they were passed to the thread worker at startup time
#endif
STATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0;
staticSealed = false;
#if USE_PTHREADS
}
#endif
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) {
staticSealed = true; // The static memory area has been initialized already in the main thread, pthreads skip this.
#if SEPARATE_ASM != 0
importScripts('{{{ SEPARATE_ASM }}}'); // load the separated-out asm.js
#endif
}
#endif
#if STACK_OVERFLOW_CHECK
// Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode.
function writeStackCookie() {
assert((STACK_MAX & 3) == 0);
HEAPU32[(STACK_MAX >> 2)-1] = 0x02135467;
HEAPU32[(STACK_MAX >> 2)-2] = 0x89BACDFE;
}
function checkStackCookie() {
if (HEAPU32[(STACK_MAX >> 2)-1] != 0x02135467 || HEAPU32[(STACK_MAX >> 2)-2] != 0x89BACDFE) {
abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x02135467, but received 0x' + HEAPU32[(STACK_MAX >> 2)-2].toString(16) + ' ' + HEAPU32[(STACK_MAX >> 2)-1].toString(16));
}
#if !SAFE_SPLIT_MEMORY
// Also test the global address 0 for integrity. This check is not compatible with SAFE_SPLIT_MEMORY though, since that mode already tests all address 0 accesses on its own.
if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) throw 'Runtime error: The application has corrupted its heap memory area (address zero)!';
#endif
}
function abortStackOverflow(allocSize) {
abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!');
}
#endif
#if ABORTING_MALLOC
function abortOnCannotGrowMemory() {
#if WASM
abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ');
#else
abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value ' + TOTAL_MEMORY + ', (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ');
#endif
}
#endif
#if ALLOW_MEMORY_GROWTH
if (!Module['reallocBuffer']) Module['reallocBuffer'] = function(size) {
var ret;
try {
if (ArrayBuffer.transfer) {
ret = ArrayBuffer.transfer(buffer, size);
} else {
var oldHEAP8 = HEAP8;
ret = new ArrayBuffer(size);
var temp = new Int8Array(ret);
temp.set(oldHEAP8);
}
} catch(e) {
return false;
}
var success = _emscripten_replace_memory(ret);
if (!success) return false;
return ret;
};
#endif
function enlargeMemory() {
#if USE_PTHREADS
abort('Cannot enlarge memory arrays, since compiling with pthreads support enabled (-s USE_PTHREADS=1).');
#else
#if ALLOW_MEMORY_GROWTH == 0
#if ABORTING_MALLOC
abortOnCannotGrowMemory();
#else
return false; // malloc will report failure
#endif
#else
// TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top.
#if ASSERTIONS
assert(HEAP32[DYNAMICTOP_PTR>>2] > TOTAL_MEMORY); // This function should only ever be called after the ceiling of the dynamic heap has already been bumped to exceed the current total size of the asm.js heap.
#endif
#if EMSCRIPTEN_TRACING
// Report old layout one last time
_emscripten_trace_report_memory_layout();
#endif
var PAGE_MULTIPLE = Module["usingWasm"] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE; // In wasm, heap size must be a multiple of 64KB. In asm.js, they need to be multiples of 16MB.
var LIMIT = 2147483648 - PAGE_MULTIPLE; // We can do one page short of 2GB as theoretical maximum.
if (HEAP32[DYNAMICTOP_PTR>>2] > LIMIT) {
#if ASSERTIONS
Module.printErr('Cannot enlarge memory, asked to go up to ' + HEAP32[DYNAMICTOP_PTR>>2] + ' bytes, but the limit is ' + LIMIT + ' bytes!');
#endif
return false;
}
var OLD_TOTAL_MEMORY = TOTAL_MEMORY;
TOTAL_MEMORY = Math.max(TOTAL_MEMORY, MIN_TOTAL_MEMORY); // So the loop below will not be infinite, and minimum asm.js memory size is 16MB.
while (TOTAL_MEMORY < HEAP32[DYNAMICTOP_PTR>>2]) { // Keep incrementing the heap size as long as it's less than what is requested.
if (TOTAL_MEMORY <= 536870912) {
TOTAL_MEMORY = alignUp(2 * TOTAL_MEMORY, PAGE_MULTIPLE); // Simple heuristic: double until 1GB...
} else {
// ..., but after that, add smaller increments towards 2GB, which we cannot reach
TOTAL_MEMORY = Math.min(alignUp((3 * TOTAL_MEMORY + 2147483648) / 4, PAGE_MULTIPLE), LIMIT);
#if ASSERTIONS
if (TOTAL_MEMORY === OLD_TOTAL_MEMORY) {
warnOnce('Cannot ask for more memory since we reached the practical limit in browsers (which is just below 2GB), so the request would have failed. Requesting only ' + TOTAL_MEMORY);
}
#endif
}
}
#if ASSERTIONS
var start = Date.now();
#endif
var replacement = Module['reallocBuffer'](TOTAL_MEMORY);
if (!replacement || replacement.byteLength != TOTAL_MEMORY) {
#if ASSERTIONS
Module.printErr('Failed to grow the heap from ' + OLD_TOTAL_MEMORY + ' bytes to ' + TOTAL_MEMORY + ' bytes, not enough memory!');
if (replacement) {
Module.printErr('Expected to get back a buffer of size ' + TOTAL_MEMORY + ' bytes, but instead got back a buffer of size ' + replacement.byteLength);
}
#endif
// restore the state to before this call, we failed
TOTAL_MEMORY = OLD_TOTAL_MEMORY;
return false;
}
// everything worked
updateGlobalBuffer(replacement);
updateGlobalBufferViews();
#if ASSERTIONS
if (!Module["usingWasm"]) {
Module.printErr('Warning: Enlarging memory arrays, this is not fast! ' + [OLD_TOTAL_MEMORY, TOTAL_MEMORY]);
}
#endif
#if EMSCRIPTEN_TRACING
_emscripten_trace_js_log_message("Emscripten", "Enlarging memory arrays from " + OLD_TOTAL_MEMORY + " to " + TOTAL_MEMORY);
// And now report the new layout
_emscripten_trace_report_memory_layout();
#endif
return true;
#endif // ALLOW_MEMORY_GROWTH
#endif // USE_PTHREADS
}
#if ALLOW_MEMORY_GROWTH
var byteLength;
try {
byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
byteLength(new ArrayBuffer(4)); // can fail on older ie
} catch(e) { // can fail on older node/v8
byteLength = function(buffer) { return buffer.byteLength; };
}
#endif
var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}};
var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}};
if (TOTAL_MEMORY < TOTAL_STACK) Module.printErr('TOTAL_MEMORY should be larger than TOTAL_STACK, was ' + TOTAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')');
// Initialize the runtime's memory
#if ASSERTIONS
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray !== undefined && Int32Array.prototype.set !== undefined,
'JS engine does not provide full typed array support');
#endif
#if IN_TEST_HARNESS
// Test runs in browsers should always be free from uncaught exceptions. If an uncaught exception is thrown, we fail browser test execution in the REPORT_RESULT() macro to output an error value.
if (ENVIRONMENT_IS_WEB) {
window.addEventListener('error', function(e) {
if (e.message.indexOf('SimulateInfiniteLoop') != -1) return;
console.error('Page threw an exception ' + e);
Module['pageThrewException'] = true;
});
}
#if USE_PTHREADS == 1
if (typeof SharedArrayBuffer === 'undefined' || typeof Atomics === 'undefined') {
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8888/report_result?skipped:%20SharedArrayBuffer%20is%20not%20supported!');
xhr.send();
setTimeout(function() { window.close() }, 2000);
}
#endif
#endif
#if USE_PTHREADS
#if !WASM
if (typeof SharedArrayBuffer !== 'undefined') {
if (!ENVIRONMENT_IS_PTHREAD) buffer = new SharedArrayBuffer(TOTAL_MEMORY);
// Currently SharedArrayBuffer does not have a slice() operation, so polyfill it in.
// Adapted from https://github.com/ttaubert/node-arraybuffer-slice, (c) 2014 Tim Taubert <tim@timtaubert.de>
// arraybuffer-slice may be freely distributed under the MIT license.
(function (undefined) {
"use strict";
function clamp(val, length) {
val = (val|0) || 0;
if (val < 0) return Math.max(val + length, 0);
return Math.min(val, length);
}
if (typeof SharedArrayBuffer !== 'undefined' && !SharedArrayBuffer.prototype.slice) {
SharedArrayBuffer.prototype.slice = function (from, to) {
var length = this.byteLength;
var begin = clamp(from, length);
var end = length;
if (to !== undefined) end = clamp(to, length);
if (begin > end) return new ArrayBuffer(0);
var num = end - begin;
var target = new ArrayBuffer(num);
var targetArray = new Uint8Array(target);
var sourceArray = new Uint8Array(this, begin, num);
targetArray.set(sourceArray);
return target;
};
}
})();
} else {
if (!ENVIRONMENT_IS_PTHREAD) buffer = new ArrayBuffer(TOTAL_MEMORY);
}
updateGlobalBufferViews();
if (typeof Atomics === 'undefined') {
// Polyfill singlethreaded atomics ops from http://lars-t-hansen.github.io/ecmascript_sharedmem/shmem.html#Atomics.add
// No thread-safety needed since we don't have multithreading support.
Atomics = {};
Atomics['add'] = function(t, i, v) { var w = t[i]; t[i] += v; return w; }
Atomics['and'] = function(t, i, v) { var w = t[i]; t[i] &= v; return w; }
Atomics['compareExchange'] = function(t, i, e, r) { var w = t[i]; if (w == e) t[i] = r; return w; }
Atomics['exchange'] = function(t, i, v) { var w = t[i]; t[i] = v; return w; }
Atomics['wait'] = function(t, i, v, o) { if (t[i] != v) return 'not-equal'; else return 'timed-out'; }
Atomics['wake'] = function(t, i, c) { return 0; }
Atomics['wakeOrRequeue'] = function(t, i1, c, i2, v) { return 0; }
Atomics['isLockFree'] = function(s) { return true; }
Atomics['load'] = function(t, i) { return t[i]; }
Atomics['or'] = function(t, i, v) { var w = t[i]; t[i] |= v; return w; }
Atomics['store'] = function(t, i, v) { t[i] = v; return v; }
Atomics['sub'] = function(t, i, v) { var w = t[i]; t[i] -= v; return w; }
Atomics['xor'] = function(t, i, v) { var w = t[i]; t[i] ^= v; return w; }
}
#else
if (!ENVIRONMENT_IS_PTHREAD) {
#if ALLOW_MEMORY_GROWTH
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE , 'maximum': {{{ WASM_MEM_MAX }}} / WASM_PAGE_SIZE, 'shared': true });
#else
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE , 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE, 'shared': true });
#endif
buffer = Module['wasmMemory'].buffer;
}
updateGlobalBufferViews();
#endif // !WASM
#else // USE_PTHREADS
#if SPLIT_MEMORY == 0
// Use a provided buffer, if there is one, or else allocate a new one
if (Module['buffer']) {
buffer = Module['buffer'];
#if ASSERTIONS
assert(buffer.byteLength === TOTAL_MEMORY, 'provided buffer should be ' + TOTAL_MEMORY + ' bytes, but it is ' + buffer.byteLength);
#endif
} else {
// Use a WebAssembly memory where available
#if WASM
if (typeof WebAssembly === 'object' && typeof WebAssembly.Memory === 'function') {
#if ASSERTIONS
assert(TOTAL_MEMORY % WASM_PAGE_SIZE === 0);
#endif // ASSERTIONS
#if ALLOW_MEMORY_GROWTH
#if WASM_MEM_MAX
#if ASSERTIONS
assert({{{ WASM_MEM_MAX }}} % WASM_PAGE_SIZE == 0);
#endif
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': {{{ WASM_MEM_MAX }}} / WASM_PAGE_SIZE });
#else
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE });
#endif // BINARYEN_MEM_MAX
#else
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });
#endif // ALLOW_MEMORY_GROWTH
buffer = Module['wasmMemory'].buffer;
} else
#endif // WASM
{
buffer = new ArrayBuffer(TOTAL_MEMORY);
}
#if ASSERTIONS
assert(buffer.byteLength === TOTAL_MEMORY);
#endif // ASSERTIONS
Module['buffer'] = buffer;
}
updateGlobalBufferViews();
#else // SPLIT_MEMORY
// make sure total memory is a multiple of the split memory size
var SPLIT_MEMORY = {{{ SPLIT_MEMORY }}};
var SPLIT_MEMORY_MASK = SPLIT_MEMORY - 1;
var SPLIT_MEMORY_BITS = -1;
var ALLOW_MEMORY_GROWTH = {{{ ALLOW_MEMORY_GROWTH }}};
var ABORTING_MALLOC = {{{ ABORTING_MALLOC }}};
Module['SPLIT_MEMORY'] = SPLIT_MEMORY;
totalMemory = TOTAL_MEMORY;
if (totalMemory % SPLIT_MEMORY) {
totalMemory += SPLIT_MEMORY - (totalMemory % SPLIT_MEMORY);
}
if (totalMemory === SPLIT_MEMORY) totalMemory *= 2;
if (totalMemory !== TOTAL_MEMORY) {
TOTAL_MEMORY = totalMemory;
#if ASSERTIONS == 2
Module.printErr('increasing TOTAL_MEMORY to ' + TOTAL_MEMORY + ' to be a multiple>1 of the split memory size ' + SPLIT_MEMORY + ')');
#endif
}
var buffers = [], HEAP8s = [], HEAP16s = [], HEAP32s = [], HEAPU8s = [], HEAPU16s = [], HEAPU32s = [], HEAPF32s = [], HEAPF64s = [];
// Allocates a split chunk, a range of memory of size SPLIT_MEMORY. Generally data is not provided, and a new
// buffer is allocated, this is what happens when malloc works. However, you can provide your own buffer,
// which then lets you access it at address [ i*SPLIT_MEMORY, (i+1)*SPLIT_MEMORY ).
// The function returns true if it succeeds. It can also throw an exception if no data is provided and
// the browser fails to allocate the buffer.
function allocateSplitChunk(i, data) {
if (buffers[i]) return false; // already taken
// any of these allocations might fail; do them all before writing anything to global state
var currBuffer = data ? data : new ArrayBuffer(SPLIT_MEMORY);
#if ASSERTIONS
assert(currBuffer instanceof ArrayBuffer);
#endif
var currHEAP8s = new Int8Array(currBuffer);
var currHEAP16s = new Int16Array(currBuffer);
var currHEAP32s = new Int32Array(currBuffer);
var currHEAPU8s = new Uint8Array(currBuffer);
var currHEAPU16s = new Uint16Array(currBuffer);
var currHEAPU32s = new Uint32Array(currBuffer);
var currHEAPF32s = new Float32Array(currBuffer);
var currHEAPF64s = new Float64Array(currBuffer);
buffers[i] = currBuffer;
HEAP8s[i] = currHEAP8s;
HEAP16s[i] = currHEAP16s;
HEAP32s[i] = currHEAP32s;
HEAPU8s[i] = currHEAPU8s;
HEAPU16s[i] = currHEAPU16s;
HEAPU32s[i] = currHEAPU32s;
HEAPF32s[i] = currHEAPF32s;
HEAPF64s[i] = currHEAPF64s;
return true;
}
function freeSplitChunk(i) {
#if ASSERTIONS
assert(buffers[i] && HEAP8s[i]);
assert(i > 0); // cannot free the first chunk
#endif
buffers[i] = HEAP8s[i] = HEAP16s[i] = HEAP32s[i] = HEAPU8s[i] = HEAPU16s[i] = HEAPU32s[i] = HEAPF32s[i] = HEAPF64s[i] = null;
}
(function() {
for (var i = 0; i < TOTAL_MEMORY / SPLIT_MEMORY; i++) {
buffers[i] = HEAP8s[i] = HEAP16s[i] = HEAP32s[i] = HEAPU8s[i] = HEAPU16s[i] = HEAPU32s[i] = HEAPF32s[i] = HEAPF64s[i] = null;
}
var temp = SPLIT_MEMORY;
while (temp) {
temp >>= 1;
SPLIT_MEMORY_BITS++;
}
allocateSplitChunk(0); // first chunk is for core runtime, static, stack, etc., always must be initialized
// support HEAP8.subarray etc.
var SHIFT_TABLE = [0, 0, 1, 0, 2, 0, 0, 0, 3];
function fake(real) {
var bytes = real[0].BYTES_PER_ELEMENT;
var shifts = SHIFT_TABLE[bytes];
#if ASSERTIONS
assert(shifts > 0 || bytes == 1);
#endif
var that = {
BYTES_PER_ELEMENT: bytes,
set: function(array, offset) {
if (offset === undefined) offset = 0;
// potentially split over multiple chunks
while (array.length > 0) {
var chunk = offset >> SPLIT_MEMORY_BITS;
var relative = offset & SPLIT_MEMORY_MASK;
if (relative + (array.length << shifts) < SPLIT_MEMORY) {
real[chunk].set(array, relative); // all fits in this chunk
break;
} else {
var currSize = SPLIT_MEMORY - relative;
#if ASSERTIONS
assert(currSize % that.BYTES_PER_ELEMENT === 0);
#endif
var lastIndex = currSize >> shifts;
real[chunk].set(array.subarray(0, lastIndex), relative);
// increments
array = array.subarray(lastIndex);
offset += currSize;
}
}
},
subarray: function(from, to) {
from = from << shifts;
var start = from >> SPLIT_MEMORY_BITS;
if (to === undefined) {
to = (start + 1) << SPLIT_MEMORY_BITS;
} else {
to = to << shifts;
}
to = Math.max(from, to); // if to is smaller, we'll get nothing anyway, same as to == from
if (from < to) {
var end = (to - 1) >> SPLIT_MEMORY_BITS; // -1, since we do not actually read the last address
#if ASSERTIONS
assert(start === end, 'subarray cannot span split chunks');
#endif
}
if (to > from && (to & SPLIT_MEMORY_MASK) == 0) {
// avoid the mask on the next line giving 0 for the end
return real[start].subarray((from & SPLIT_MEMORY_MASK) >> shifts); // just return to the end of the chunk
}
return real[start].subarray((from & SPLIT_MEMORY_MASK) >> shifts, (to & SPLIT_MEMORY_MASK) >> shifts);
},
buffer: {
slice: function(from, to) {
#if ASSERTIONS
assert(to, 'TODO: this is an actual copy, so we could support a slice across multiple chunks');
#endif
return new Uint8Array(HEAPU8.subarray(from, to)).buffer;
},
},
};
return that;
}
HEAP8 = fake(HEAP8s);
HEAP16 = fake(HEAP16s);
HEAP32 = fake(HEAP32s);
HEAPU8 = fake(HEAPU8s);
HEAPU16 = fake(HEAPU16s);
HEAPU32 = fake(HEAPU32s);
HEAPF32 = fake(HEAPF32s);
HEAPF64 = fake(HEAPF64s);
})();
#if SAFE_SPLIT_MEMORY
function checkPtr(ptr, shifts) {
if (ptr <= 0) abort('segmentation fault storing to address ' + ptr);
if (ptr !== ((ptr >> shifts) << shifts)) abort('alignment error storing to address ' + ptr + ', which was expected to be aligned to a shift of ' + shifts);
if ((ptr >> SPLIT_MEMORY_BITS) !== (ptr + Math.pow(2, shifts) - 1 >> SPLIT_MEMORY_BITS)) abort('segmentation fault, write spans split chunks ' + [ptr, shifts]);
}
#endif
function get8(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 0);
#endif
return HEAP8s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 0] | 0;
}
function get16(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 1);
#endif
return HEAP16s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 1] | 0;
}
function get32(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
return HEAP32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2] | 0;
}
function getU8(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 0);
#endif
return HEAPU8s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 0] | 0;
}
function getU16(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 1);
#endif
return HEAPU16s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 1] | 0;
}
function getU32(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
return HEAPU32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2] >>> 0;
}
function getF32(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
return +HEAPF32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2];
}
function getF64(ptr) {
ptr = ptr | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 3);
#endif
return +HEAPF64s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 3];
}
function set8(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 0);
#endif
HEAP8s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 0] = value;
}
function set16(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 1);
#endif
HEAP16s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 1] = value;
}
function set32(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
HEAP32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2] = value;
}
function setU8(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 0);
#endif
HEAPU8s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 0] = value;
}
function setU16(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 1);
#endif
HEAPU16s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 1] = value;
}
function setU32(ptr, value) {
ptr = ptr | 0;
value = value | 0;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
HEAPU32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2] = value;
}
function setF32(ptr, value) {
ptr = ptr | 0;
value = +value;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 2);
#endif
HEAPF32s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 2] = value;
}
function setF64(ptr, value) {
ptr = ptr | 0;
value = +value;
#if SAFE_SPLIT_MEMORY
checkPtr(ptr, 3);
#endif
HEAPF64s[ptr >> SPLIT_MEMORY_BITS][(ptr & SPLIT_MEMORY_MASK) >> 3] = value;
}
#endif // SPLIT_MEMORY
#endif // USE_PTHREADS
function getTotalMemory() {
return TOTAL_MEMORY;
}
// Endianness check (note: assumes compiler arch was little-endian)
#if SAFE_SPLIT_MEMORY == 0
#if USE_PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) {
#endif
HEAP32[0] = 0x63736d65; /* 'emsc' */
#if USE_PTHREADS
} else {
if (HEAP32[0] !== 0x63736d65) throw 'Runtime error: The application has corrupted its heap memory area (address zero)!';
}
#endif
HEAP16[1] = 0x6373;
if (HEAPU8[2] !== 0x73 || HEAPU8[3] !== 0x63) throw 'Runtime error: expected the system to be little-endian!';
#endif
function callRuntimeCallbacks(callbacks) {
while(callbacks.length > 0) {
var callback = callbacks.shift();
if (typeof callback == 'function') {
callback();
continue;
}
var func = callback.func;
if (typeof func === 'number') {
if (callback.arg === undefined) {
Module['dynCall_v'](func);
} else {
Module['dynCall_vi'](func, callback.arg);
}
} else {
func(callback.arg === undefined ? null : callback.arg);
}
}
}
var __ATPRERUN__ = []; // functions called before the runtime is initialized
var __ATINIT__ = []; // functions called during startup
var __ATMAIN__ = []; // functions called when main() is to be run
var __ATEXIT__ = []; // functions called during shutdown
var __ATPOSTRUN__ = []; // functions called after the main() is called
var runtimeInitialized = false;
var runtimeExited = false;
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) runtimeInitialized = true; // The runtime is hosted in the main thread, and bits shared to pthreads via SharedArrayBuffer. No need to init again in pthread.
#endif
function preRun() {
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
#endif
// compatibility - merge in anything from Module['preRun'] at this time
if (Module['preRun']) {
if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
while (Module['preRun'].length) {
addOnPreRun(Module['preRun'].shift());
}
}
callRuntimeCallbacks(__ATPRERUN__);
}
function ensureInitRuntime() {
#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
#endif
if (runtimeInitialized) return;
runtimeInitialized = true;
#if USE_PTHREADS
// Pass the thread address inside the asm.js scope to store it for fast access that avoids the need for a FFI out.
__register_pthread_ptr(PThread.mainThreadBlock, /*isMainBrowserThread=*/!ENVIRONMENT_IS_WORKER, /*isMainRuntimeThread=*/1);
#endif
callRuntimeCallbacks(__ATINIT__);
}
function preMain() {
#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
#endif
callRuntimeCallbacks(__ATMAIN__);
}
function exitRuntime() {
#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
#endif
callRuntimeCallbacks(__ATEXIT__);
runtimeExited = true;
}
function postRun() {
#if STACK_OVERFLOW_CHECK
checkStackCookie();
#endif
#if USE_PTHREADS
if (ENVIRONMENT_IS_PTHREAD) return; // PThreads reuse the runtime from the main thread.
#endif
// compatibility - merge in anything from Module['postRun'] at this time
if (Module['postRun']) {
if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
while (Module['postRun'].length) {
addOnPostRun(Module['postRun'].shift());
}
}
callRuntimeCallbacks(__ATPOSTRUN__);
}
function addOnPreRun(cb) {
__ATPRERUN__.unshift(cb);
}
function addOnInit(cb) {
__ATINIT__.unshift(cb);
}
function addOnPreMain(cb) {
__ATMAIN__.unshift(cb);
}
function addOnExit(cb) {
__ATEXIT__.unshift(cb);
}
function addOnPostRun(cb) {
__ATPOSTRUN__.unshift(cb);
}
// Deprecated: This function should not be called because it is unsafe and does not provide
// a maximum length limit of how many bytes it is allowed to write. Prefer calling the
// function stringToUTF8Array() instead, which takes in a maximum length that can be used
// to be secure from out of bounds writes.
/** @deprecated */
function writeStringToMemory(string, buffer, dontAddNull) {
warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!');
var /** @type {number} */ lastChar, /** @type {number} */ end;
if (dontAddNull) {
// stringToUTF8Array always appends null. If we don't want to do that, remember the
// character that existed at the location where the null will be placed, and restore
// that after the write (below).
end = buffer + lengthBytesUTF8(string);
lastChar = HEAP8[end];
}
stringToUTF8(string, buffer, Infinity);
if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character.
}
function writeArrayToMemory(array, buffer) {
#if ASSERTIONS
assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)')
#endif
HEAP8.set(array, buffer);
}
function writeAsciiToMemory(str, buffer, dontAddNull) {
for (var i = 0; i < str.length; ++i) {
#if ASSERTIONS
assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff);
#endif
{{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}};
}
// Null-terminate the pointer to the HEAP.
if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}};
}
{{{ unSign }}}
{{{ reSign }}}
#if LEGACY_VM_SUPPORT
// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )
if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) {
var ah = a >>> 16;
var al = a & 0xffff;
var bh = b >>> 16;
var bl = b & 0xffff;
return (al*bl + ((ah*bl + al*bh) << 16))|0;
};
Math.imul = Math['imul'];
#if PRECISE_F32
#if PRECISE_F32 == 1
if (!Math['fround']) {
var froundBuffer = new Float32Array(1);
Math['fround'] = function(x) { froundBuffer[0] = x; return froundBuffer[0] };
}
#else // 2
if (!Math['fround']) Math['fround'] = function(x) { return x };
#endif
Math.fround = Math['fround'];
#else
#if SIMD
if (!Math['fround']) Math['fround'] = function(x) { return x };
#endif
#endif
if (!Math['clz32']) Math['clz32'] = function(x) {
x = x >>> 0;
for (var i = 0; i < 32; i++) {
if (x & (1 << (31 - i))) return i;
}
return 32;
};
Math.clz32 = Math['clz32']
if (!Math['trunc']) Math['trunc'] = function(x) {
return x < 0 ? Math.ceil(x) : Math.floor(x);
};
Math.trunc = Math['trunc'];
#else // LEGACY_VM_SUPPORT
#if ASSERTIONS
assert(Math['imul'] && Math['fround'] && Math['clz32'] && Math['trunc'], 'this is a legacy browser, build with LEGACY_VM_SUPPORT');
#endif
#endif // LEGACY_VM_SUPPORT
var Math_abs = Math.abs;
var Math_cos = Math.cos;
var Math_sin = Math.sin;
var Math_tan = Math.tan;
var Math_acos = Math.acos;
var Math_asin = Math.asin;
var Math_atan = Math.atan;
var Math_atan2 = Math.atan2;
var Math_exp = Math.exp;
var Math_log = Math.log;
var Math_sqrt = Math.sqrt;
var Math_ceil = Math.ceil;
var Math_floor = Math.floor;
var Math_pow = Math.pow;
var Math_imul = Math.imul;
var Math_fround = Math.fround;
var Math_round = Math.round;
var Math_min = Math.min;
var Math_max = Math.max;
var Math_clz32 = Math.clz32;
var Math_trunc = Math.trunc;
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
// decrement it. Incrementing must happen in a place like
// PRE_RUN_ADDITIONS (used by emcc to add file preloading).
// Note that you can add dependencies in preRun, even though
// it happens right before run - run will be postponed until
// the dependencies are met.
var runDependencies = 0;
var runDependencyWatcher = null;
var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
#if ASSERTIONS
var runDependencyTracking = {};
#endif
function getUniqueRunDependency(id) {
#if ASSERTIONS
var orig = id;
while (1) {
if (!runDependencyTracking[id]) return id;
id = orig + Math.random();
}
#endif
return id;
}
function addRunDependency(id) {
#if USE_PTHREADS
// We should never get here in pthreads (could no-op this out if called in pthreads, but that might indicate a bug in caller side,
// so good to be very explicit)
assert(!ENVIRONMENT_IS_PTHREAD);
#endif
runDependencies++;
if (Module['monitorRunDependencies']) {
Module['monitorRunDependencies'](runDependencies);
}
#if ASSERTIONS
if (id) {
assert(!runDependencyTracking[id]);
runDependencyTracking[id] = 1;
if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
// Check for missing dependencies every few seconds
runDependencyWatcher = setInterval(function() {
if (ABORT) {
clearInterval(runDependencyWatcher);
runDependencyWatcher = null;
return;
}
var shown = false;
for (var dep in runDependencyTracking) {
if (!shown) {
shown = true;
Module.printErr('still waiting on run dependencies:');
}
Module.printErr('dependency: ' + dep);
}
if (shown) {
Module.printErr('(end of list)');
}
}, 10000);
}
} else {
Module.printErr('warning: run dependency added without ID');
}
#endif
}
function removeRunDependency(id) {
runDependencies--;
if (Module['monitorRunDependencies']) {
Module['monitorRunDependencies'](runDependencies);
}
#if ASSERTIONS
if (id) {
assert(runDependencyTracking[id]);
delete runDependencyTracking[id];
} else {
Module.printErr('warning: run dependency removed without ID');
}
#endif
if (runDependencies == 0) {
if (runDependencyWatcher !== null) {
clearInterval(runDependencyWatcher);
runDependencyWatcher = null;
}
if (dependenciesFulfilled) {
var callback = dependenciesFulfilled;
dependenciesFulfilled = null;
callback(); // can add another dependenciesFulfilled
}
}
}
Module["preloadedImages"] = {}; // maps url to image data
Module["preloadedAudios"] = {}; // maps url to audio data
#if (WASM != 0) && (MAIN_MODULE != 0)
Module["preloadedWasm"] = {}; // maps url to wasm instance exports
#endif
#if PGO
var PGOMonitor = {
called: {},
dump: function() {
var dead = [];
for (var i = 0; i < this.allGenerated.length; i++) {
var func = this.allGenerated[i];
if (!this.called[func]) dead.push(func);
}
Module.print('-s DEAD_FUNCTIONS=\'' + JSON.stringify(dead) + '\'\n');
}
};
Module['PGOMonitor'] = PGOMonitor;
__ATEXIT__.push(function() { PGOMonitor.dump() });
addOnPreRun(function() { addRunDependency('pgo') });
#endif
#if RELOCATABLE
{{{
(function() {
// add in RUNTIME_LINKED_LIBS, if provided
if (RUNTIME_LINKED_LIBS.length > 0) {
return "if (!Module['dynamicLibraries']) Module['dynamicLibraries'] = [];\n" +
"Module['dynamicLibraries'] = " + JSON.stringify(RUNTIME_LINKED_LIBS) + ".concat(Module['dynamicLibraries']);\n";
}
return '';
})()
}}}
addOnPreRun(function() {
function loadDynamicLibraries(libs) {
if (libs) {
libs.forEach(function(lib) {
loadDynamicLibrary(lib);
});
}
if (Module['asm']['runPostSets']) {
Module['asm']['runPostSets']();
}
}
// if we can load dynamic libraries synchronously, do so, otherwise, preload
#if WASM
if (Module['dynamicLibraries'] && Module['dynamicLibraries'].length > 0 && !Module['readBinary']) {
// we can't read binary data synchronously, so preload
addRunDependency('preload_dynamicLibraries');
var binaries = [];
Module['dynamicLibraries'].forEach(function(lib) {
fetch(lib, { credentials: 'same-origin' }).then(function(response) {
if (!response['ok']) {
throw "failed to load wasm binary file at '" + lib + "'";
}
return response['arrayBuffer']();
}).then(function(buffer) {
var binary = new Uint8Array(buffer);
binaries.push(binary);
if (binaries.length === Module['dynamicLibraries'].length) {
// we got them all, wonderful
loadDynamicLibraries(binaries);
removeRunDependency('preload_dynamicLibraries');
}
});
});
return;
}
#endif
loadDynamicLibraries(Module['dynamicLibraries']);
});
#if ASSERTIONS
function lookupSymbol(ptr) { // for a pointer, print out all symbols that resolve to it
var ret = [];
for (var i in Module) {
if (Module[i] === ptr) ret.push(i);
}
print(ptr + ' is ' + ret);
}
#endif
#endif
var memoryInitializer = null;
#if USE_PTHREADS
#if PTHREAD_HINT_NUM_CORES < 0
if (!ENVIRONMENT_IS_PTHREAD) addOnPreRun(function() {
addRunDependency('pthreads_querycores');
var bg = document.createElement('div');
bg.style = "position: absolute; top: 0%; left: 0%; width: 100%; height: 100%; background-color: black; z-index:1001; -moz-opacity: 0.8; opacity:.80; filter: alpha(opacity=80);";
var div = document.createElement('div');
var default_num_cores = navigator.hardwareConcurrency || 4;
var hwConcurrency = navigator.hardwareConcurrency ? ("says " + navigator.hardwareConcurrency) : "is not available";
var html = '<div style="width: 100%; text-align:center;"> Thread setup</div> <br /> Number of logical cores: <input type="number" style="width: 50px;" value="'
+ default_num_cores + '" min="1" max="32" id="thread_setup_num_logical_cores"></input> <br /><span style="font-size: 75%;">(<span style="font-family: monospace;">navigator.hardwareConcurrency</span> '
+ hwConcurrency + ')</span> <br />';
#if PTHREAD_POOL_SIZE < 0
html += 'PThread pool size: <input type="number" style="width: 50px;" value="'
+ default_num_cores + '" min="1" max="32" id="thread_setup_pthread_pool_size"></input> <br />';
#endif
html += ' <br /> <input type="button" id="thread_setup_button_go" value="Go"></input>';
div.innerHTML = html;
div.style = 'position: absolute; top: 35%; left: 35%; width: 30%; height: 150px; padding: 16px; border: 16px solid gray; background-color: white; z-index:1002; overflow: auto;';
document.body.appendChild(bg);
document.body.appendChild(div);
var goButton = document.getElementById('thread_setup_button_go');
goButton.onclick = function() {
var num_logical_cores = parseInt(document.getElementById('thread_setup_num_logical_cores').value);
_emscripten_force_num_logical_cores(num_logical_cores);
#if PTHREAD_POOL_SIZE < 0
var pthread_pool_size = parseInt(document.getElementById('thread_setup_pthread_pool_size').value);
PThread.allocateUnusedWorkers(pthread_pool_size, function() { removeRunDependency('pthreads_querycores'); });
#else
removeRunDependency('pthreads_querycores');
#endif
document.body.removeChild(bg);
document.body.removeChild(div);
}
});
#endif
#endif
#if PTHREAD_POOL_SIZE > 0
// To work around https://bugzilla.mozilla.org/show_bug.cgi?id=1049079, warm up a worker pool before starting up the application.
if (!ENVIRONMENT_IS_PTHREAD) addOnPreRun(function() { if (typeof SharedArrayBuffer !== 'undefined') { addRunDependency('pthreads'); PThread.allocateUnusedWorkers({{{PTHREAD_POOL_SIZE}}}, function() { removeRunDependency('pthreads'); }); }});
#endif
#if ASSERTIONS
#if NO_FILESYSTEM
var /* show errors on likely calls to FS when it was not included */ FS = {
error: function() {
abort('Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -s FORCE_FILESYSTEM=1');
},
init: function() { FS.error() },
createDataFile: function() { FS.error() },
createPreloadedFile: function() { FS.error() },
createLazyFile: function() { FS.error() },
open: function() { FS.error() },
mkdev: function() { FS.error() },
registerDevice: function() { FS.error() },
analyzePath: function() { FS.error() },
loadFilesFromDB: function() { FS.error() },
ErrnoError: function ErrnoError() { FS.error() },
};
Module['FS_createDataFile'] = FS.createDataFile;
Module['FS_createPreloadedFile'] = FS.createPreloadedFile;
#endif
#endif
#if CYBERDWARF
var cyberDWARFFile = '{{{ BUNDLED_CD_DEBUG_FILE }}}';
#endif
#include "URIUtils.js"
#if WASM
function integrateWasmJS() {
// wasm.js has several methods for creating the compiled code module here:
// * 'native-wasm' : use native WebAssembly support in the browser
// * 'interpret-s-expr': load s-expression code from a .wast and interpret
// * 'interpret-binary': load binary wasm and interpret
// * 'interpret-asm2wasm': load asm.js code, translate to wasm, and interpret
// * 'asmjs': no wasm, just load the asm.js code and use that (good for testing)
// The method is set at compile time (BINARYEN_METHOD)
// The method can be a comma-separated list, in which case, we will try the
// options one by one. Some of them can fail gracefully, and then we can try
// the next.
// inputs
var method = '{{{ BINARYEN_METHOD }}}';
var wasmTextFile = '{{{ WASM_TEXT_FILE }}}';
var wasmBinaryFile = '{{{ WASM_BINARY_FILE }}}';
var asmjsCodeFile = '{{{ ASMJS_CODE_FILE }}}';
if (typeof Module['locateFile'] === 'function') {
if (!isDataURI(wasmTextFile)) {
wasmTextFile = Module['locateFile'](wasmTextFile);
}
if (!isDataURI(wasmBinaryFile)) {
wasmBinaryFile = Module['locateFile'](wasmBinaryFile);
}
if (!isDataURI(asmjsCodeFile)) {
asmjsCodeFile = Module['locateFile'](asmjsCodeFile);
}
}
// utilities
var wasmPageSize = 64*1024;
var info = {
'global': null,
'env': null,
'asm2wasm': asm2wasmImports,
'parent': Module // Module inside wasm-js.cpp refers to wasm-js.cpp; this allows access to the outside program.
};
var exports = null;
#if BINARYEN_METHOD != 'native-wasm'
function lookupImport(mod, base) {
var lookup = info;
if (mod.indexOf('.') < 0) {
lookup = (lookup || {})[mod];
} else {
var parts = mod.split('.');
lookup = (lookup || {})[parts[0]];
lookup = (lookup || {})[parts[1]];
}
if (base) {
lookup = (lookup || {})[base];
}
if (lookup === undefined) {
abort('bad lookupImport to (' + mod + ').' + base);
}
return lookup;
}
#endif // BINARYEN_METHOD != 'native-wasm'
function mergeMemory(newBuffer) {
// The wasm instance creates its memory. But static init code might have written to
// buffer already, including the mem init file, and we must copy it over in a proper merge.
// TODO: avoid this copy, by avoiding such static init writes
// TODO: in shorter term, just copy up to the last static init write
var oldBuffer = Module['buffer'];
if (newBuffer.byteLength < oldBuffer.byteLength) {
Module['printErr']('the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here');
}
var oldView = new Int8Array(oldBuffer);
var newView = new Int8Array(newBuffer);
#if MEM_INIT_IN_WASM == 0
// If we have a mem init file, do not trample it
if (!memoryInitializer) {
oldView.set(newView.subarray(Module['STATIC_BASE'], Module['STATIC_BASE'] + Module['STATIC_BUMP']), Module['STATIC_BASE']);
}
#endif
newView.set(oldView);
updateGlobalBuffer(newBuffer);
updateGlobalBufferViews();
}
function fixImports(imports) {
#if WASM_BACKEND
var ret = {};
for (var i in imports) {
var fixed = i;
if (fixed[0] == '_') fixed = fixed.substr(1);
ret[fixed] = imports[i];
}
return ret;
#else
return imports;
#endif // WASM_BACKEND
}
function getBinary() {
try {
if (Module['wasmBinary']) {
return new Uint8Array(Module['wasmBinary']);
}
#if SUPPORT_BASE64_EMBEDDING
var binary = tryParseAsDataURI(wasmBinaryFile);
if (binary) {
return binary;
}
#endif
if (Module['readBinary']) {
return Module['readBinary'](wasmBinaryFile);
} else {
throw "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)";
}
}
catch (err) {
abort(err);
}
}
function getBinaryPromise() {
// if we don't have the binary yet, and have the Fetch api, use that
// in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web
if (!Module['wasmBinary'] && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function') {
return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) {
if (!response['ok']) {
throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
}
return response['arrayBuffer']();
}).catch(function () {
return getBinary();
});
}
// Otherwise, getBinary should be able to get it synchronously
return new Promise(function(resolve, reject) {
resolve(getBinary());
});
}
// do-method functions
#if BINARYEN_METHOD != 'native-wasm'
function doJustAsm(global, env, providedBuffer) {
// if no Module.asm, or it's the method handler helper (see below), then apply
// the asmjs
if (typeof Module['asm'] !== 'function' || Module['asm'] === methodHandler) {
if (!Module['asmPreload']) {
// you can load the .asm.js file before this, to avoid this sync xhr and eval
{{{ makeEval("eval(Module['read'](asmjsCodeFile));") }}} // set Module.asm
} else {
Module['asm'] = Module['asmPreload'];
}
}
if (typeof Module['asm'] !== 'function') {
Module['printErr']('asm evalling did not set the module properly');
return false;
}
return Module['asm'](global, env, providedBuffer);
}
#endif // BINARYEN_METHOD != 'native-wasm'
function doNativeWasm(global, env, providedBuffer) {
if (typeof WebAssembly !== 'object') {
#if BINARYEN_METHOD == 'native-wasm'
#if ASSERTIONS
// when the method is just native-wasm, our error message can be very specific
abort('No WebAssembly support found. Build with -s WASM=0 to target JavaScript instead.');
#endif
#endif
Module['printErr']('no native wasm support detected');
return false;
}
// prepare memory import
if (!(Module['wasmMemory'] instanceof WebAssembly.Memory)) {
Module['printErr']('no native wasm Memory in use');
return false;
}
env['memory'] = Module['wasmMemory'];
// Load the wasm module and create an instance of using native support in the JS engine.
info['global'] = {
'NaN': NaN,
'Infinity': Infinity
};
info['global.Math'] = Math;
info['env'] = env;
// handle a generated wasm instance, receiving its exports and
// performing other necessary setup
function receiveInstance(instance, module) {
exports = instance.exports;
if (exports.memory) mergeMemory(exports.memory);
Module['asm'] = exports;
Module["usingWasm"] = true;
#if WASM_BACKEND
// wasm backend stack goes down
STACKTOP = STACK_BASE + TOTAL_STACK;
STACK_MAX = STACK_BASE;
// can't call stackRestore() here since this function can be called
// synchronously before stackRestore() is declared.
Module["asm"]["stackRestore"](STACKTOP);
#endif
#if USE_PTHREADS
// Keep a reference to the compiled module so we can post it to the workers.
Module['wasmModule'] = module;
// Instantiation is synchronous in pthreads and we assert on run dependencies.
if(!ENVIRONMENT_IS_PTHREAD) removeRunDependency('wasm-instantiate');
#else
removeRunDependency('wasm-instantiate');
#endif
}
#if USE_PTHREADS
if (!ENVIRONMENT_IS_PTHREAD) {
addRunDependency('wasm-instantiate'); // we can't run yet (except in a pthread, where we have a custom sync instantiator)
}
#else
addRunDependency('wasm-instantiate');
#endif
// User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
// to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel
// to any other async startup actions they are performing.
if (Module['instantiateWasm']) {
try {
return Module['instantiateWasm'](info, receiveInstance);
} catch(e) {
Module['printErr']('Module.instantiateWasm callback failed with error: ' + e);
return false;
}
}
#if BINARYEN_ASYNC_COMPILATION
#if RUNTIME_LOGGING
Module['printErr']('asynchronously preparing wasm');
#endif
#if ASSERTIONS
// Async compilation can be confusing when an error on the page overwrites Module
// (for example, if the order of elements is wrong, and the one defining Module is
// later), so we save Module and check it later.
var trueModule = Module;
#endif
function receiveInstantiatedSource(output) {
// 'output' is a WebAssemblyInstantiatedSource object which has both the module and instance.
// receiveInstance() will swap in the exports (to Module.asm) so they can be called
#if ASSERTIONS
assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?');
trueModule = null;
#endif
receiveInstance(output['instance'], output['module']);
}
function instantiateArrayBuffer(receiver) {
getBinaryPromise().then(function(binary) {
return WebAssembly.instantiate(binary, info);
}).then(receiver).catch(function(reason) {
Module['printErr']('failed to asynchronously prepare wasm: ' + reason);
abort(reason);
});
}
// Prefer streaming instantiation if available.
if (!Module['wasmBinary'] &&
typeof WebAssembly.instantiateStreaming === 'function' &&
!isDataURI(wasmBinaryFile) &&
typeof fetch === 'function') {
WebAssembly.instantiateStreaming(fetch(wasmBinaryFile, { credentials: 'same-origin' }), info)
.then(receiveInstantiatedSource)
.catch(function(reason) {
// We expect the most common failure cause to be a bad MIME type for the binary,
// in which case falling back to ArrayBuffer instantiation should work.
Module['printErr']('wasm streaming compile failed: ' + reason);
Module['printErr']('falling back to ArrayBuffer instantiation');
instantiateArrayBuffer(receiveInstantiatedSource);
});
} else {
instantiateArrayBuffer(receiveInstantiatedSource);
}
return {}; // no exports yet; we'll fill them in later
#else
var instance;
try {
instance = new WebAssembly.Instance(new WebAssembly.Module(getBinary()), info)
} catch (e) {
Module['printErr']('failed to compile wasm module: ' + e);
if (e.toString().indexOf('imported Memory with incompatible size') >= 0) {
Module['printErr']('Memory size incompatibility issues may be due to changing TOTAL_MEMORY at runtime to something too large. Use ALLOW_MEMORY_GROWTH to allow any size memory (and also make sure not to set TOTAL_MEMORY at runtime to something smaller than it was at compile time).');
}
return false;
}
receiveInstance(instance);
return exports;
#endif
}
#if BINARYEN_METHOD != 'native-wasm'
function doWasmPolyfill(global, env, providedBuffer, method) {
if (typeof WasmJS !== 'function') {
Module['printErr']('WasmJS not detected - polyfill not bundled?');
return false;
}
// Use wasm.js to polyfill and execute code in a wasm interpreter.
var wasmJS = WasmJS({});
// XXX don't be confused. Module here is in the outside program. wasmJS is the inner wasm-js.cpp.
wasmJS['outside'] = Module; // Inside wasm-js.cpp, Module['outside'] reaches the outside module.
// Information for the instance of the module.
wasmJS['info'] = info;
wasmJS['lookupImport'] = lookupImport;
assert(providedBuffer === Module['buffer']); // we should not even need to pass it as a 3rd arg for wasm, but that's the asm.js way.
info.global = global;
info.env = env;
// polyfill interpreter expects an ArrayBuffer
assert(providedBuffer === Module['buffer']);
env['memory'] = providedBuffer;
assert(env['memory'] instanceof ArrayBuffer);
wasmJS['providedTotalMemory'] = Module['buffer'].byteLength;
// Prepare to generate wasm, using either asm2wasm or s-exprs
var code;
if (method === 'interpret-binary') {
code = getBinary();
} else {
code = Module['read'](method == 'interpret-asm2wasm' ? asmjsCodeFile : wasmTextFile);
}
var temp;
if (method == 'interpret-asm2wasm') {
temp = wasmJS['_malloc'](code.length + 1);
wasmJS['writeAsciiToMemory'](code, temp);
wasmJS['_load_asm2wasm'](temp);
} else if (method === 'interpret-s-expr') {
temp = wasmJS['_malloc'](code.length + 1);
wasmJS['writeAsciiToMemory'](code, temp);
wasmJS['_load_s_expr2wasm'](temp);
} else if (method === 'interpret-binary') {
temp = wasmJS['_malloc'](code.length);
wasmJS['HEAPU8'].set(code, temp);
wasmJS['_load_binary2wasm'](temp, code.length);
} else {
throw 'what? ' + method;
}
wasmJS['_free'](temp);
wasmJS['_instantiate'](temp);
if (Module['newBuffer']) {
mergeMemory(Module['newBuffer']);
Module['newBuffer'] = null;
}
exports = wasmJS['asmExports'];
return exports;
}
#endif // BINARYEN_METHOD != 'native-wasm'
// We may have a preloaded value in Module.asm, save it
Module['asmPreload'] = Module['asm'];
// Memory growth integration code
var asmjsReallocBuffer = Module['reallocBuffer'];
var wasmReallocBuffer = function(size) {
var PAGE_MULTIPLE = Module["usingWasm"] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE; // In wasm, heap size must be a multiple of 64KB. In asm.js, they need to be multiples of 16MB.
size = alignUp(size, PAGE_MULTIPLE); // round up to wasm page size
var old = Module['buffer'];
var oldSize = old.byteLength;
if (Module["usingWasm"]) {
// native wasm support
try {
var result = Module['wasmMemory'].grow((size - oldSize) / wasmPageSize); // .grow() takes a delta compared to the previous size
if (result !== (-1 | 0)) {
// success in native wasm memory growth, get the buffer from the memory
return Module['buffer'] = Module['wasmMemory'].buffer;
} else {
return null;
}
} catch(e) {
#if ASSERTIONS
console.error('Module.reallocBuffer: Attempted to grow from ' + oldSize + ' bytes to ' + size + ' bytes, but got error: ' + e);
#endif
return null;
}
}
#if BINARYEN_METHOD != 'native-wasm'
else {
// wasm interpreter support
exports['__growWasmMemory']((size - oldSize) / wasmPageSize); // tiny wasm method that just does grow_memory
// in interpreter, we replace Module.buffer if we allocate
return Module['buffer'] !== old ? Module['buffer'] : null; // if it was reallocated, it changed
}
#endif // BINARYEN_METHOD != 'native-wasm'
};
Module['reallocBuffer'] = function(size) {
if (finalMethod === 'asmjs') {
return asmjsReallocBuffer(size);
} else {
return wasmReallocBuffer(size);
}
};
// we may try more than one; this is the final one, that worked and we are using
var finalMethod = '';
// Provide an "asm.js function" for the application, called to "link" the asm.js module. We instantiate
// the wasm module at that time, and it receives imports and provides exports and so forth, the app
// doesn't need to care that it is wasm or olyfilled wasm or asm.js.
Module['asm'] = function(global, env, providedBuffer) {
#if BINARYEN_METHOD != 'native-wasm'
global = fixImports(global);
#endif
env = fixImports(env);
// import table
if (!env['table']) {
var TABLE_SIZE = Module['wasmTableSize'];
if (TABLE_SIZE === undefined) TABLE_SIZE = 1024; // works in binaryen interpreter at least
var MAX_TABLE_SIZE = Module['wasmMaxTableSize'];
if (typeof WebAssembly === 'object' && typeof WebAssembly.Table === 'function') {
if (MAX_TABLE_SIZE !== undefined) {
env['table'] = new WebAssembly.Table({ 'initial': TABLE_SIZE, 'maximum': MAX_TABLE_SIZE, 'element': 'anyfunc' });
} else {
env['table'] = new WebAssembly.Table({ 'initial': TABLE_SIZE, element: 'anyfunc' });
}
} else {
env['table'] = new Array(TABLE_SIZE); // works in binaryen interpreter at least
}
Module['wasmTable'] = env['table'];
}
if (!env['memoryBase']) {
env['memoryBase'] = Module['STATIC_BASE']; // tell the memory segments where to place themselves
}
if (!env['tableBase']) {
env['tableBase'] = 0; // table starts at 0 by default, in dynamic linking this will change
}
// try the methods. each should return the exports if it succeeded
var exports;
#if BINARYEN_METHOD == 'native-wasm'
exports = doNativeWasm(global, env, providedBuffer);
#else // native-wasm
#if BINARYEN_METHOD == 'asmjs'
exports = doJustAsm(global, env, providedBuffer);
#else
var methods = method.split(',');
for (var i = 0; i < methods.length; i++) {
var curr = methods[i];
#if RUNTIME_LOGGING
Module['printErr']('trying binaryen method: ' + curr);
#endif
finalMethod = curr;
if (curr === 'native-wasm') {
if (exports = doNativeWasm(global, env, providedBuffer)) break;
} else if (curr === 'asmjs') {
if (exports = doJustAsm(global, env, providedBuffer)) break;
} else if (curr === 'interpret-asm2wasm' || curr === 'interpret-s-expr' || curr === 'interpret-binary') {
if (exports = doWasmPolyfill(global, env, providedBuffer, curr)) break;
} else {
abort('bad method: ' + curr);
}
}
#endif // asmjs
#endif // native-wasm
#if ASSERTIONS
assert(exports, 'no binaryen method succeeded. consider enabling more options, like interpreting, if you want that: https://github.com/kripken/emscripten/wiki/WebAssembly#binaryen-methods');
#else
assert(exports, 'no binaryen method succeeded.');
#endif
#if RUNTIME_LOGGING
Module['printErr']('binaryen method succeeded.');
#endif
return exports;
};
var methodHandler = Module['asm']; // note our method handler, as we may modify Module['asm'] later
}
integrateWasmJS();
#endif
// === Body ===
// {{PREAMBLE_ADDITIONS}}
var STACK_ALIGN = {{{ STACK_ALIGN }}};
#if ASSERTIONS
// stack management, and other functionality that is provided by the compiled code,
// should not be used before it is ready
stackSave = stackRestore = stackAlloc = setTempRet0 = getTempRet0 = function() {
abort('cannot use the stack before compiled code is ready to run, and has provided stack access');
};
#endif
function staticAlloc(size) {
assert(!staticSealed);
var ret = STATICTOP;
STATICTOP = (STATICTOP + size + 15) & -16;
return ret;
}
function dynamicAlloc(size) {
assert(DYNAMICTOP_PTR);
var ret = HEAP32[DYNAMICTOP_PTR>>2];
var end = (ret + size + 15) & -16;
HEAP32[DYNAMICTOP_PTR>>2] = end;
if (end >= TOTAL_MEMORY) {
var success = enlargeMemory();
if (!success) {
HEAP32[DYNAMICTOP_PTR>>2] = ret;
return 0;
}
}
return ret;
}
{{{ alignMemory }}}
{{{ getNativeTypeSize }}}
function warnOnce(text) {
if (!warnOnce.shown) warnOnce.shown = {};
if (!warnOnce.shown[text]) {
warnOnce.shown[text] = 1;
Module.printErr(text);
}
}
var asm2wasmImports = { // special asm2wasm imports
"f64-rem": function(x, y) {
return x % y;
},
"debugger": function() {
debugger;
}
#if NEED_ALL_ASM2WASM_IMPORTS
,
"f64-to-int": function(x) {
return x | 0;
},
"i32s-div": function(x, y) {
return ((x | 0) / (y | 0)) | 0;
},
"i32u-div": function(x, y) {
return ((x >>> 0) / (y >>> 0)) >>> 0;
},
"i32s-rem": function(x, y) {
return ((x | 0) % (y | 0)) | 0;
},
"i32u-rem": function(x, y) {
return ((x >>> 0) % (y >>> 0)) >>> 0;
}
#endif // NEED_ALL_ASM2WASM_IMPORTS
};
#if RELOCATABLE
var loadedDynamicLibraries = [];
function loadDynamicLibrary(lib) {
var libModule;
#if WASM
var bin;
if (lib.buffer) {
// we were provided the binary, in a typed array
bin = lib;
} else {
// load the binary synchronously
bin = Module['readBinary'](lib);
}
libModule = loadWebAssemblyModule(bin);
#else
var src = Module['read'](lib);
libModule = eval(src)(
alignFunctionTables(),
Module
);
#endif
// add symbols into global namespace TODO: weak linking etc.
for (var sym in libModule) {
if (!Module.hasOwnProperty(sym)) {
Module[sym] = libModule[sym];
}
#if ASSERTIONS == 2
else if (sym[0] === '_') {
var curr = Module[sym], next = libModule[sym];
// don't warn on functions - might be odr, linkonce_odr, etc.
if (!(typeof curr === 'function' && typeof next === 'function')) {
Module.printErr("warning: trying to dynamically load symbol '" + sym + "' (from '" + lib + "') that already exists (duplicate symbol? or weak linking, which isn't supported yet?)"); // + [curr, ' vs ', next]);
}
}
#endif
}
loadedDynamicLibraries.push(libModule);
}
#if WASM
// Loads a side module from binary data
function loadWebAssemblyModule(binary, loadAsync) {
var int32View = new Uint32Array(new Uint8Array(binary.subarray(0, 24)).buffer);
assert(int32View[0] == 0x6d736100, 'need to see wasm magic number'); // \0wasm
// we should see the dylink section right after the magic number and wasm version
assert(binary[8] === 0, 'need the dylink section to be first')
var next = 9;
function getLEB() {
var ret = 0;
var mul = 1;
while (1) {
var byte = binary[next++];
ret += ((byte & 0x7f) * mul);
mul *= 0x80;
if (!(byte & 0x80)) break;
}
return ret;
}
var sectionSize = getLEB();
assert(binary[next] === 6); next++; // size of "dylink" string
assert(binary[next] === 'd'.charCodeAt(0)); next++;
assert(binary[next] === 'y'.charCodeAt(0)); next++;
assert(binary[next] === 'l'.charCodeAt(0)); next++;
assert(binary[next] === 'i'.charCodeAt(0)); next++;
assert(binary[next] === 'n'.charCodeAt(0)); next++;
assert(binary[next] === 'k'.charCodeAt(0)); next++;
var memorySize = getLEB();
var memoryAlign = getLEB();
var tableSize = getLEB();
var tableAlign = getLEB();
// alignments are powers of 2
memoryAlign = Math.pow(2, memoryAlign);
tableAlign = Math.pow(2, tableAlign);
// finalize alignments and verify them
memoryAlign = Math.max(memoryAlign, STACK_ALIGN); // we at least need stack alignment
assert(tableAlign === 1);
// prepare memory
var memoryStart = alignMemory(getMemory(memorySize + memoryAlign), memoryAlign); // TODO: add to cleanups
// The static area consists of explicitly initialized data, followed by zero-initialized data.
// The latter may need zeroing out if the MAIN_MODULE has already used this memory area before
// dlopen'ing the SIDE_MODULE. Since we don't know the size of the explicitly initialized data
// here, we just zero the whole thing, which is suboptimal, but should at least resolve bugs
// from uninitialized memory.
for (var i = memoryStart; i < memoryStart + memorySize; ++i) HEAP8[i] = 0;
// prepare env imports
var env = Module['asmLibraryArg'];
// TODO: use only memoryBase and tableBase, need to update asm.js backend
var table = Module['wasmTable'];
var oldTableSize = table.length;
env['memoryBase'] = env['gb'] = memoryStart;
env['tableBase'] = env['fb'] = oldTableSize;
var originalTable = table;
table.grow(tableSize);
assert(table === originalTable);
// zero-initialize memory and table TODO: in some cases we can tell it is already zero initialized
for (var i = env['memoryBase']; i < env['memoryBase'] + memorySize; i++) {
HEAP8[i] = 0;
}
for (var i = env['tableBase']; i < env['tableBase'] + tableSize; i++) {
table.set(i, null);
}
// copy currently exported symbols so the new module can import them
for (var x in Module) {
if (!(x in env)) {
env[x] = Module[x];
}
}
var info = {
global: {
'NaN': NaN,
'Infinity': Infinity,
},
'global.Math': Math,
env: env,
'asm2wasm': asm2wasmImports
};
#if ASSERTIONS
var oldTable = [];
for (var i = 0; i < oldTableSize; i++) {
oldTable.push(table.get(i));
}
#endif
function postInstantiation(instance) {
var exports = {};
#if ASSERTIONS
// the table should be unchanged
assert(table === originalTable);
assert(table === Module['wasmTable']);
if (instance.exports['table']) {
assert(table === instance.exports['table']);
}
// the old part of the table should be unchanged
for (var i = 0; i < oldTableSize; i++) {
assert(table.get(i) === oldTable[i], 'old table entries must remain the same');
}
// verify that the new table region was filled in
for (var i = 0; i < tableSize; i++) {
assert(table.get(oldTableSize + i) !== undefined, 'table entry was not filled in');
}
#endif
for (var e in instance.exports) {
var value = instance.exports[e];
if (typeof value === 'object') {
// a breaking change in the wasm spec, globals are now objects
// https://github.com/WebAssembly/mutable-global/issues/1
value = value.value;
}
if (typeof value === 'number') {
// relocate it - modules export the absolute value, they can't relocate before they export
#if EMULATED_FUNCTION_POINTERS
// it may be a function pointer
if (e.substr(0, 3) == 'fp$' && typeof instance.exports[e.substr(3)] === 'function') {
value = value + env['tableBase'];
} else {
#endif
value = value + env['memoryBase'];
#if EMULATED_FUNCTION_POINTERS
}
#endif
}
exports[e] = value;
}
// initialize the module
var init = exports['__post_instantiate'];
if (init) {
if (runtimeInitialized) {
init();
} else {
// we aren't ready to run compiled code yet
__ATINIT__.push(init);
}
}
return exports;
}
if (loadAsync) {
return WebAssembly.instantiate(binary, info).then(function(result) {
return postInstantiation(result.instance);
});
} else {
var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), info);
return postInstantiation(instance);
}
}
Module['loadWebAssemblyModule'] = loadWebAssemblyModule;
#endif // WASM
#endif // RELOCATABLE
#if EMULATED_FUNCTION_POINTERS
function getFunctionTables(module) {
if (!module) module = Module;
var tables = {};
for (var t in module) {
if (/^FUNCTION_TABLE_.*/.test(t)) {
var table = module[t];
if (typeof table === 'object') tables[t.substr('FUNCTION_TABLE_'.length)] = table;
}
}
return tables;
}
function alignFunctionTables(module) {
var tables = getFunctionTables(module);
var maxx = 0;
for (var sig in tables) {
maxx = Math.max(maxx, tables[sig].length);
}
assert(maxx >= 0);
for (var sig in tables) {
var table = tables[sig];
while (table.length < maxx) table.push(0);
}
return maxx;
}
#if RELOCATABLE
// register functions from a new module being loaded
function registerFunctions(sigs, newModule) {
sigs.forEach(function(sig) {
if (!Module['FUNCTION_TABLE_' + sig]) {
Module['FUNCTION_TABLE_' + sig] = [];
}
});
var oldMaxx = alignFunctionTables(); // align the new tables we may have just added
var newMaxx = alignFunctionTables(newModule);
var maxx = oldMaxx + newMaxx;
sigs.forEach(function(sig) {
var newTable = newModule['FUNCTION_TABLE_' + sig];
var oldTable = Module['FUNCTION_TABLE_' + sig];
assert(newTable !== oldTable);
assert(oldTable.length === oldMaxx);
for (var i = 0; i < newTable.length; i++) {
oldTable.push(newTable[i]);
}
assert(oldTable.length === maxx);
});
assert(maxx === alignFunctionTables()); // align the ones we didn't touch
}
// export this so side modules can use it
Module['registerFunctions'] = registerFunctions;
#endif // RELOCATABLE
#endif // EMULATED_FUNCTION_POINTERS
#if WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS
var jsCallStartIndex = {{{ JSCALL_START_INDEX }}};
var jsCallSigOrder = {{{ JSON.stringify(JSCALL_SIG_ORDER) }}};
var jsCallNumSigs = Object.keys(jsCallSigOrder).length;
var functionPointers = new Array(jsCallNumSigs * {{{ RESERVED_FUNCTION_POINTERS }}});
#else // WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS == 0
var jsCallStartIndex = 1;
var functionPointers = new Array({{{ RESERVED_FUNCTION_POINTERS }}});
#endif // WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS
// 'sig' parameter is only used on LLVM wasm backend
function addFunction(func, sig) {
#if WASM_BACKEND
assert(typeof sig !== 'undefined',
'Second argument of addFunction should be a wasm function signature ' +
'string');
#endif // WASM_BACKEND
#if ASSERTIONS
if (typeof sig === 'undefined') {
Module.printErr('warning: addFunction(): You should provide a wasm function signature string as a second argument. This is not necessary for asm.js and asm2wasm, but is required for the LLVM wasm backend, so it is recommended for full portability.');
}
#endif // ASSERTIONS
#if EMULATED_FUNCTION_POINTERS == 0
#if WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS
var base = jsCallSigOrder[sig] * {{{ RESERVED_FUNCTION_POINTERS }}};
#else // WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS == 0
var base = 0;
#endif // WASM_BACKEND_WITH_RESERVED_FUNCTION_POINTERS
for (var i = base; i < base + {{{ RESERVED_FUNCTION_POINTERS }}}; i++) {
if (!functionPointers[i]) {
functionPointers[i] = func;
return jsCallStartIndex + i;
}
}
throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
#else
#if WASM
// we can simply append to the wasm table
var table = Module['wasmTable'];
var ret = table.length;
table.grow(1);
table.set(ret, func);
return ret;
#else
alignFunctionTables(); // XXX we should rely on this being an invariant
var tables = getFunctionTables();
var ret = -1;
for (var sig in tables) {
var table = tables[sig];
if (ret < 0) ret = table.length;
else assert(ret === table.length);
table.push(func);
}
return ret;
#endif
#endif
}
function removeFunction(index) {
#if EMULATED_FUNCTION_POINTERS == 0
functionPointers[index-jsCallStartIndex] = null;
#else
alignFunctionTables(); // XXX we should rely on this being an invariant
var tables = getFunctionTables();
for (var sig in tables) {
tables[sig][index] = null;
}
#endif
}
var funcWrappers = {};
function getFuncWrapper(func, sig) {
if (!func) return; // on null pointer, return undefined
assert(sig);
if (!funcWrappers[sig]) {
funcWrappers[sig] = {};
}
var sigCache = funcWrappers[sig];
if (!sigCache[func]) {
// optimize away arguments usage in common cases
if (sig.length === 1) {
sigCache[func] = function dynCall_wrapper() {
return dynCall(sig, func);
};
} else if (sig.length === 2) {
sigCache[func] = function dynCall_wrapper(arg) {
return dynCall(sig, func, [arg]);
};
} else {
// general case
sigCache[func] = function dynCall_wrapper() {
return dynCall(sig, func, Array.prototype.slice.call(arguments));
};
}
}
return sigCache[func];
}
#if RUNTIME_DEBUG
var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times
var printObjectList = [];
function prettyPrint(arg) {
if (typeof arg == 'undefined') return '!UNDEFINED!';
if (typeof arg == 'boolean') arg = arg + 0;
if (!arg) return arg;
var index = printObjectList.indexOf(arg);
if (index >= 0) return '<' + arg + '|' + index + '>';
if (arg.toString() == '[object HTMLImageElement]') {
return arg + '\n\n';
}
if (arg.byteLength) {
return '{' + Array.prototype.slice.call(arg, 0, Math.min(arg.length, 400)) + '}'; // Useful for correct arrays, less so for compiled arrays, see the code below for that
var buf = new ArrayBuffer(32);
var i8buf = new Int8Array(buf);
var i16buf = new Int16Array(buf);
var f32buf = new Float32Array(buf);
switch(arg.toString()) {
case '[object Uint8Array]':
i8buf.set(arg.subarray(0, 32));
break;
case '[object Float32Array]':
f32buf.set(arg.subarray(0, 5));
break;
case '[object Uint16Array]':
i16buf.set(arg.subarray(0, 16));
break;
default:
alert('unknown array for debugging: ' + arg);
throw 'see alert';
}
var ret = '{' + arg.byteLength + ':\n';
var arr = Array.prototype.slice.call(i8buf);
ret += 'i8:' + arr.toString().replace(/,/g, ',') + '\n';
arr = Array.prototype.slice.call(f32buf, 0, 8);
ret += 'f32:' + arr.toString().replace(/,/g, ',') + '}';
return ret;
}
if (typeof arg == 'object') {
printObjectList.push(arg);
return '<' + arg + '|' + (printObjectList.length-1) + '>';
}
if (typeof arg == 'number') {
if (arg > 0) return '0x' + arg.toString(16) + ' (' + arg + ')';
}
return arg;
}
#endif
function makeBigInt(low, high, unsigned) {
return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0));
}
function dynCall(sig, ptr, args) {
if (args && args.length) {
#if ASSERTIONS
assert(args.length == sig.length-1);
#endif
#if ASSERTIONS
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
#endif
return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
} else {
#if ASSERTIONS
assert(sig.length == 1);
#endif
#if ASSERTIONS
assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
#endif
return Module['dynCall_' + sig].call(null, ptr);
}
}
#if RELOCATABLE
// tempRet0 is normally handled in the module. but in relocatable code,
// we need to share a single one among all the modules, so they all call
// out.
var tempRet0 = 0;
var setTempRet0 = function(value) {
tempRet0 = value;
}
var getTempRet0 = function() {
return tempRet0;
}
#endif // RELOCATABLE
#if RETAIN_COMPILER_SETTINGS
var compilerSettings = {{{ JSON.stringify(makeRetainedCompilerSettings()) }}} ;
function getCompilerSetting(name) {
if (!(name in compilerSettings)) return 'invalid compiler setting: ' + name;
return compilerSettings[name];
}
#else // RETAIN_COMPILER_SETTINGS
#if ASSERTIONS
function getCompilerSetting(name) {
throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for getCompilerSetting or emscripten_get_compiler_setting to work';
}
#endif // ASSERTIONS
#endif // RETAIN_COMPILER_SETTINGS
var Runtime = {
// FIXME backwards compatibility layer for ports. Support some Runtime.*
// for now, fix it there, then remove it from here. That way we
// can minimize any period of breakage.
dynCall: dynCall, // for SDL2 port
#if ASSERTIONS
// helpful errors
getTempRet0: function() { abort('getTempRet0() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
staticAlloc: function() { abort('staticAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
stackAlloc: function() { abort('stackAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
#endif
};
// The address globals begin at. Very low in memory, for code size and optimization opportunities.
// Above 0 is static memory, starting with globals.
// Then the stack.
// Then 'dynamic' memory for sbrk.
var GLOBAL_BASE = {{{ GLOBAL_BASE }}};
#if RELOCATABLE
GLOBAL_BASE = alignMemory(GLOBAL_BASE, {{{ MAX_GLOBAL_ALIGN || 1 }}});
#endif
index f6c9842ff..9f83181eb 100644
--- a/emsdk/emscripten/tag-1.38.4/src/support.js
+++ b/emsdk/emscripten/tag-1.38.4/src/support.js
@@ -158,7 +158,33 @@ function loadWebAssemblyModule(binary) {
'Infinity': Infinity,
},
'global.Math': Math,
- env: env
+ env: env,
+ 'asm2wasm': { // special asm2wasm imports
+ "f64-rem": function(x, y) {
+ return x % y;
+ },
+ "debugger": function() {
+ debugger;
+ }
+#if NEED_ALL_ASM2WASM_IMPORTS
+ ,
+ "f64-to-int": function(x) {
+ return x | 0;
+ },
+ "i32s-div": function(x, y) {
+ return ((x | 0) / (y | 0)) | 0;
+ },
+ "i32u-div": function(x, y) {
+ return ((x >>> 0) / (y >>> 0)) >>> 0;
+ },
+ "i32s-rem": function(x, y) {
+ return ((x | 0) % (y | 0)) | 0;
+ },
+ "i32u-rem": function(x, y) {
+ return ((x >>> 0) % (y >>> 0)) >>> 0;
+ }
+#endif // NEED_ALL_ASM2WASM_IMPORTS
+ },
};
#if ASSERTIONS
var oldTable = [];
diff --git a/emsdk/binaryen/master/src/passes/FuncCastEmulation.cpp b/emsdk/binaryen/master/src/passes/FuncCastEmulation.cpp diff --git a/emsdk/binaryen/master/src/passes/FuncCastEmulation.cpp b/emsdk/binaryen/master/src/passes/FuncCastEmulation.cpp
index 013e9403..d95fc282 100644 index 013e9403..d95fc282 100644
--- a/emsdk/binaryen/tag-1.38.4/src/passes/FuncCastEmulation.cpp --- a/emsdk/binaryen/tag-1.38.10/src/passes/FuncCastEmulation.cpp
+++ b/emsdk/binaryen/tag-1.38.4/src/passes/FuncCastEmulation.cpp +++ b/emsdk/binaryen/tag-1.38.10/src/passes/FuncCastEmulation.cpp
@@ -39,7 +39,7 @@ namespace wasm { @@ -39,7 +39,7 @@ namespace wasm {
// This should be enough for everybody. (As described above, we need this // This should be enough for everybody. (As described above, we need this
// to match when dynamically linking, and also dynamic linking is why we // to match when dynamically linking, and also dynamic linking is why we
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment