// === Auto-generated preamble library stuff === //======================================== // Runtime code shared with compiler //======================================== {{RUNTIME}} Module['Runtime'] = Runtime; #if ASM_JS #if RESERVED_FUNCTION_POINTERS function jsCall() { var args = Array.prototype.slice.call(arguments); return Runtime.functionPointers[args[0]].apply(null, args.slice(1)); } #endif #endif #if BENCHMARK Module.realPrint = Module.print; Module.print = Module.printErr = function(){}; #endif #if SAFE_HEAP #if ASM_JS == 0 //======================================== // Debugging tools - Heap //======================================== var HEAP_WATCHED = []; var HEAP_HISTORY = []; function SAFE_HEAP_CLEAR(dest) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP clear: ' + dest); #endif HEAP_HISTORY[dest] = undefined; } var SAFE_HEAP_ERRORS = 0; var ACCEPTABLE_SAFE_HEAP_ERRORS = 0; function SAFE_HEAP_ACCESS(dest, type, store, ignore, storeValue) { //if (dest === A_NUMBER) Module.print ([dest, type, store, ignore, storeValue] + ' ' + stackTrace()); // Something like this may be useful, in debugging if (dest <= 0) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest); #if USE_TYPED_ARRAYS // When using typed arrays, reads over the top of TOTAL_MEMORY will fail silently, so we must // correct that by growing TOTAL_MEMORY as needed. Without typed arrays, memory is a normal // JS array so it will work (potentially slowly, depending on the engine). if (!ignore && dest >= Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault ' + (store ? ('storing value ' + storeValue) : 'loading') + ' type ' + type + ' at address ' + dest + '. Heap ends at address ' + Math.max(DYNAMICTOP, STATICTOP)); assert(ignore || DYNAMICTOP <= TOTAL_MEMORY); #endif #if USE_TYPED_ARRAYS == 2 return; // It is legitimate to violate the load-store assumption in this case #endif if (type && type.charAt(type.length-1) == '*') type = 'i32'; // pointers are ints, for our purposes here // Note that this will pass even with unions: You can store X, load X, then store Y and load Y. // You cannot, however, do the nonportable act of store X and load Y! if (store) { HEAP_HISTORY[dest] = ignore ? null : type; } else { #if USE_TYPED_ARRAYS == 0 if (!HEAP[dest] && HEAP[dest] !== 0 && HEAP[dest] !== false && !ignore) { // false can be the result of a mathop comparator var error = true; try { if (HEAP[dest].toString() === 'NaN') error = false; // NaN is acceptable, as a double value } catch(e){} if (error) throw('Warning: Reading an invalid value at ' + dest + ' :: ' + stackTrace() + '\n'); } #endif if (type === null) return; var history = HEAP_HISTORY[dest]; if (history === null) return; if (!ignore) assert(history, 'Must have a history for a safe heap load! ' + dest + ':' + type); // Warning - bit fields in C structs cause loads+stores for each store, so // they will show up here... // assert((history && history[0]) /* || HEAP[dest] === 0 */, "Loading from where there was no store! " + dest + ',' + HEAP[dest] + ',' + type + ', \n\n' + stackTrace() + '\n'); // if (history[0].type !== type) { if (history !== type && !ignore) { Module.print('Load-store consistency assumption failure! ' + dest); Module.print('\n'); Module.print(JSON.stringify(history)); Module.print('\n'); Module.print('LOAD: ' + type + ', ' + stackTrace()); Module.print('\n'); SAFE_HEAP_ERRORS++; assert(SAFE_HEAP_ERRORS <= ACCEPTABLE_SAFE_HEAP_ERRORS, 'Load-store consistency assumption failure!'); } } } function SAFE_HEAP_STORE(dest, value, type, ignore) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP store: ' + [dest, type, value, ignore]); #endif if (!ignore && !value && (value === null || value === undefined)) { throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + stackTrace() + '\n'); } //if (!ignore && (value === Infinity || value === -Infinity || isNaN(value))) throw [value, typeof value, stackTrace()]; SAFE_HEAP_ACCESS(dest, type, true, ignore, value); if (dest in HEAP_WATCHED) { Module.print((new Error()).stack); throw "Bad store!" + dest; } #if USE_TYPED_ARRAYS == 2 // Check alignment switch(type) { case 'i16': assert(dest % 2 == 0); break; case 'i32': assert(dest % 4 == 0); break; case 'i64': assert(dest % 8 == 0); break; case 'float': assert(dest % 4 == 0); break; #if DOUBLE_MODE == 1 case 'double': assert(dest % 4 == 0); break; #else case 'double': assert(dest % 4 == 0); break; #endif } #endif setValue(dest, value, type, 1); } function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) { SAFE_HEAP_ACCESS(dest, type, false, ignore); #if SAFE_HEAP_LOG Module.print('SAFE_HEAP load: ' + [dest, type, getValue(dest, type, 1), ignore]); #endif #if USE_TYPED_ARRAYS == 2 // Check alignment switch(type) { case 'i16': assert(dest % 2 == 0); break; case 'i32': assert(dest % 4 == 0); break; case 'i64': assert(dest % 8 == 0); break; case 'float': assert(dest % 4 == 0); break; #if DOUBLE_MODE == 1 case 'double': assert(dest % 4 == 0); break; #else case 'double': assert(dest % 4 == 0); break; #endif } #endif var ret = getValue(dest, type, 1); if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1); return ret; } function SAFE_HEAP_COPY_HISTORY(dest, src) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP copy: ' + [dest, src]); #endif HEAP_HISTORY[dest] = HEAP_HISTORY[src]; SAFE_HEAP_ACCESS(dest, HEAP_HISTORY[dest] || null, true, false); } function SAFE_HEAP_FILL_HISTORY(from, to, type) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP fill: ' + [from, to, type]); #endif for (var i = from; i < to; i++) { HEAP_HISTORY[i] = type; } } //========================================== #else // ASM_JS 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); } } function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]); #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 (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when storing ' + bytes + ' bytes to address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); } function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) { 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 (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when loading ' + bytes + ' bytes from address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); 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]); #endif return ret; } 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; } #endif #endif #if CHECK_HEAP_ALIGN //======================================== // Debugging tools - alignment check //======================================== function CHECK_ALIGN_8(addr) { assert((addr & 7) == 0, "address must be 8-byte aligned, is " + addr + "!"); return addr; } function CHECK_ALIGN_4(addr) { assert((addr & 3) == 0, "address must be 4-byte aligned, is " + addr + "!"); return addr; } function CHECK_ALIGN_2(addr) { assert((addr & 1) == 0, "address must be 2-byte aligned!"); return addr; } #endif #if CHECK_OVERFLOWS //======================================== // Debugging tools - Mathop overflows //======================================== function CHECK_OVERFLOW(value, bits, ignore, sig) { if (ignore) return value; var twopbits = Math.pow(2, bits); var twopbits1 = Math.pow(2, bits-1); // For signedness issue here, see settings.js, CHECK_SIGNED_OVERFLOWS #if CHECK_SIGNED_OVERFLOWS if (value === Infinity || value === -Infinity || value >= twopbits1 || value < -twopbits1) { throw 'SignedOverflow'; if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) throw 'Overflow'; } #else if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) { throw 'Overflow'; } #endif #if CORRECT_OVERFLOWS // Fail on >32 bits - we warned at compile time if (bits <= 32) { value = value & (twopbits - 1); } #endif return value; } #endif #if LABEL_DEBUG //======================================== // Debugging tools - Code flow progress //======================================== var INDENT = ''; #endif #if EXECUTION_TIMEOUT //======================================== // Debugging tools - Execution timeout //======================================== var START_TIME = Date.now(); #endif //======================================== // Runtime essentials //======================================== var __THREW__ = 0; // Used in checking for thrown exceptions. #if ASM_JS == 0 var setjmpId = 1; // Used in setjmp/longjmp var setjmpLabels = {}; #endif var ABORT = false; // whether we are quitting the application. no code should run after this. set in exit() and abort() var EXITSTATUS = 0; var undef = 0; // tempInt is used for 32-bit signed values or smaller. tempBigInt is used // for 32-bit unsigned values or more than 32 bits. TODO: audit all uses of tempInt var tempValue, tempInt, tempBigInt, tempInt2, tempBigInt2, tempPair, tempBigIntI, tempBigIntR, tempBigIntS, tempBigIntP, tempBigIntD, tempDouble, tempFloat; #if USE_TYPED_ARRAYS == 2 var tempI64, tempI64b; var tempRet0, tempRet1, tempRet2, tempRet3, tempRet4, tempRet5, tempRet6, tempRet7, tempRet8, tempRet9; #endif 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 if (!func) { #if NO_DYNAMIC_EXECUTION == 0 try { func = eval('_' + ident); // explicit lookup } catch(e) {} #else abort('NO_DYNAMIC_EXECUTION was set, cannot eval - ccall/cwrap are not functional'); #endif } assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)'); return func; } var cwrap, ccall; (function(){ var stack = 0; var JSfuncs = { 'stackSave' : function() { stack = Runtime.stackSave(); }, 'stackRestore' : function() { Runtime.stackRestore(stack); }, // type conversion from js to c 'arrayToC' : function(arr) { var ret = Runtime.stackAlloc(arr.length); writeArrayToMemory(arr, ret); return ret; }, 'stringToC' : function(str) { var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string ret = Runtime.stackAlloc(str.length + 1); // +1 for the trailing '\0' writeStringToMemory(str, ret); } return ret; } }; // For fast lookup of conversion functions var toC = {'string' : JSfuncs['stringToC'], 'array' : JSfuncs['arrayToC']}; // C calling interface. A convenient way to call C functions (in C files, or // defined with extern "C"). // // Note: ccall/cwrap use the C stack for temporary values. If you pass a string // then it is only alive until the call is complete. If the code being // called saves the pointer to be used later, it may point to invalid // data. If you need a string to live forever, you can create it (and // must later delete it manually!) using malloc and writeStringToMemory, // for example. // // Note: LLVM optimizations can inline and remove functions, after which you will not be // able to call them. Closure can also do so. To avoid that, add your function to // the exports using something like // // -s EXPORTED_FUNCTIONS='["_main", "_myfunc"]' // // @param ident The name of the C function (note that C++ functions will be name-mangled - use extern "C") // @param returnType The return type of the function, one of the JS types 'number', 'string' or 'array' (use 'number' for any C pointer, and // 'array' for JavaScript arrays and typed arrays; note that arrays are 8-bit). // @param argTypes An array of the types of arguments for the function (if there are no arguments, this can be ommitted). Types are as in returnType, // except that 'array' is not possible (there is no way for us to know the length of the array) // @param args An array of the arguments to the function, as native JS values (as in returnType) // Note that string arguments will be stored on the stack (the JS string will become a C string on the stack). // @return The return value, as a native JS value (as in returnType) ccall = function ccallFunc(ident, returnType, argTypes, args) { var func = getCFunc(ident); var cArgs = []; #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 = Runtime.stackSave(); cArgs[i] = converter(args[i]); } else { cArgs[i] = args[i]; } } } var ret = func.apply(null, cArgs); if (returnType === 'string') ret = Pointer_stringify(ret); if (stack !== 0) JSfuncs['stackRestore'](); return ret; } var sourceRegex = /^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/; function parseJSFunc(jsfunc) { // Match the body and the return value of a javascript function source var parsed = jsfunc.toString().match(sourceRegex).slice(1); return {arguments : parsed[0], body : parsed[1], returnValue: parsed[2]} } var JSsource = {}; for (var fun in JSfuncs) { if (JSfuncs.hasOwnProperty(fun)) { // Elements of toCsource are arrays of three items: // the code, and the return value JSsource[fun] = parseJSFunc(JSfuncs[fun]); } } // Returns a native JS wrapper for a C function. This is similar to ccall, but // returns a function you can call repeatedly in a normal way. For example: // // var my_function = cwrap('my_c_function', 'number', ['number', 'number']); // alert(my_function(5, 22)); // alert(my_function(99, 12)); // cwrap = function cwrap(ident, returnType, 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; } // Creation of the arguments list (["$1","$2",...,"$nargs"]) var argNames = argTypes.map(function(x,i){return '$'+i}); var funcstr = "(function(" + argNames.join(',') + ") {"; var nargs = argTypes.length; if (!numericArgs) { // Generate the code needed to convert the arguments from javascript // values to pointers funcstr += JSsource['stackSave'].body + ';'; for (var i = 0; i < nargs; i++) { var arg = argNames[i], type = argTypes[i]; if (type === 'number') continue; var convertCode = JSsource[type + 'ToC']; // [code, return] funcstr += 'var ' + convertCode.arguments + ' = ' + arg + ';'; funcstr += convertCode.body + ';'; funcstr += arg + '=' + convertCode.returnValue + ';'; } } // When the code is compressed, the name of cfunc is not literally 'cfunc' anymore var cfuncname = parseJSFunc(function(){return cfunc}).returnValue; // Call the function funcstr += 'var ret = ' + cfuncname + '(' + argNames.join(',') + ');'; if (!numericRet) { // Return type can only by 'string' or 'number' // Convert the result to a string var strgfy = parseJSFunc(function(){return Pointer_stringify}).returnValue; funcstr += 'ret = ' + strgfy + '(ret);'; } if (!numericArgs) { // If we had a stack, restore it funcstr += JSsource['stackRestore'].body + ';'; } funcstr += 'return ret})'; #if NO_DYNAMIC_EXECUTION == 0 return eval(funcstr); #else abort('NO_DYNAMIC_EXECUTION was set, cannot eval - ccall is not functional'); #endif }; })(); Module["cwrap"] = cwrap; Module["ccall"] = ccall; // Sets a value in memory in a dynamic way at run-time. Uses the // type data. This is the same as makeSetValue, except that // makeSetValue is done at compile-time and generates the needed // code then, whereas this function picks the right code at // run-time. // Note that setValue and getValue only do *aligned* writes and reads! // Note that ccall uses JS types as for defining types, while setValue and // getValue need LLVM types ('i8', 'i32') - this is a lower-level operation 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 } Module['setValue'] = setValue; // Parallel to setValue. 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 setValue: ' + 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 setValue: ' + type); } #if SAFE_HEAP } #endif return null; } Module['getValue'] = getValue; 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 Module['ALLOC_NORMAL'] = ALLOC_NORMAL; Module['ALLOC_STACK'] = ALLOC_STACK; Module['ALLOC_STATIC'] = ALLOC_STATIC; Module['ALLOC_DYNAMIC'] = ALLOC_DYNAMIC; Module['ALLOC_NONE'] = ALLOC_NONE; // 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_* 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 = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length)); } if (zeroinit) { var ptr = ret, stop; #if USE_TYPED_ARRAYS == 2 assert((ret & 3) == 0); stop = ret + (size & ~3); for (; ptr < stop; ptr += 4) { {{{ makeSetValue('ptr', '0', '0', 'i32', null, true) }}}; } #endif stop = ret + size; while (ptr < stop) { {{{ makeSetValue('ptr++', '0', '0', 'i8', null, true) }}}; } return ret; } #if USE_TYPED_ARRAYS == 2 if (singleType === 'i8') { if (slab.subarray || slab.slice) { HEAPU8.set(slab, ret); } else { HEAPU8.set(new Uint8Array(slab), ret); } return ret; } #endif var i = 0, type, typeSize, previousType; while (i < size) { var curr = slab[i]; if (typeof curr === 'function') { curr = Runtime.getFunctionIndex(curr); } type = singleType || types[i]; if (type === 0) { i++; continue; } #if ASSERTIONS assert(type, 'Must know what type to store in allocate!'); #endif #if USE_TYPED_ARRAYS == 2 if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later #endif setValue(ret+i, curr, type); // no need to look up size unless type changes, so cache it if (previousType !== type) { typeSize = Runtime.getNativeTypeSize(type); previousType = type; } i += typeSize; } return ret; } Module['allocate'] = allocate; function Pointer_stringify(ptr, /* optional */ length) { // TODO: use TextDecoder // Find the length, and check for UTF while doing so var hasUtf = false; var t; var i = 0; while (1) { #if ASSERTIONS assert(ptr + i < TOTAL_MEMORY); #endif t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; if (t >= 128) hasUtf = true; else if (t == 0 && !length) break; i++; if (length && i == length) break; } if (!length) length = i; var ret = ''; #if USE_TYPED_ARRAYS == 2 if (!hasUtf) { 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; } #endif var utf8 = new Runtime.UTF8Processor(); for (i = 0; i < length; i++) { #if ASSERTIONS assert(ptr + i < TOTAL_MEMORY); #endif t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; ret += utf8.processCChar(t); } return ret; } Module['Pointer_stringify'] = Pointer_stringify; // 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. function UTF16ToString(ptr) { 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); } } Module['UTF16ToString'] = UTF16ToString; // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', // null-terminated and encoded in UTF16LE form. The copy will require at most (str.length*2+1)*2 bytes of space in the HEAP. function stringToUTF16(str, outPtr) { for(var i = 0; i < str.length; ++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', 'i*2', 'codeUnit', 'i16') }}}; } // Null-terminate the pointer to the HEAP. {{{ makeSetValue('outPtr', 'str.length*2', 0, 'i16') }}}; } Module['stringToUTF16'] = stringToUTF16; // Given a pointer 'ptr' to a null-terminated UTF32LE-encoded string in the emscripten HEAP, returns // a copy of that string as a Javascript String object. function UTF32ToString(ptr) { 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. if (utf32 >= 0x10000) { var ch = utf32 - 0x10000; str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); } else { str += String.fromCharCode(utf32); } } } Module['UTF32ToString'] = UTF32ToString; // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr', // null-terminated and encoded in UTF32LE form. The copy will require at most (str.length+1)*4 bytes of space in the HEAP, // but can use less, since str.length does not return the number of characters in the string, but the number of UTF-16 code units in the string. function stringToUTF32(str, outPtr) { var iChar = 0; for(var iCodeUnit = 0; iCodeUnit < str.length; ++iCodeUnit) { // 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. var codeUnit = str.charCodeAt(iCodeUnit); // possibly a lead surrogate if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) { var trailSurrogate = str.charCodeAt(++iCodeUnit); codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF); } {{{ makeSetValue('outPtr', 'iChar*4', 'codeUnit', 'i32') }}}; ++iChar; } // Null-terminate the pointer to the HEAP. {{{ makeSetValue('outPtr', 'iChar*4', 0, 'i32') }}}; } Module['stringToUTF32'] = stringToUTF32; function demangle(func) { var i = 3; // params, etc. var basicTypes = { 'v': 'void', 'b': 'bool', 'c': 'char', 's': 'short', 'i': 'int', 'l': 'long', 'f': 'float', 'd': 'double', 'w': 'wchar_t', 'a': 'signed char', 'h': 'unsigned char', 't': 'unsigned short', 'j': 'unsigned int', 'm': 'unsigned long', 'x': 'long long', 'y': 'unsigned long long', 'z': '...' }; var subs = []; var first = true; function dump(x) { //return; if (x) Module.print(x); Module.print(func); var pre = ''; for (var a = 0; a < i; a++) pre += ' '; Module.print (pre + '^'); } function parseNested() { i++; if (func[i] === 'K') i++; // ignore const var parts = []; while (func[i] !== 'E') { if (func[i] === 'S') { // substitution i++; var next = func.indexOf('_', i); var num = func.substring(i, next) || 0; parts.push(subs[num] || '?'); i = next+1; continue; } if (func[i] === 'C') { // constructor parts.push(parts[parts.length-1]); i += 2; continue; } var size = parseInt(func.substr(i)); var pre = size.toString().length; if (!size || !pre) { i--; break; } // counter i++ below us var curr = func.substr(i + pre, size); parts.push(curr); subs.push(curr); i += pre + size; } i++; // skip E return parts; } function parse(rawList, limit, allowVoid) { // main parser limit = limit || Infinity; var ret = '', list = []; function flushList() { return '(' + list.join(', ') + ')'; } var name; if (func[i] === 'N') { // namespaced N-E name = parseNested().join('::'); limit--; if (limit === 0) return rawList ? [name] : name; } else { // not namespaced if (func[i] === 'K' || (first && func[i] === 'L')) i++; // ignore const and first 'L' var size = parseInt(func.substr(i)); if (size) { var pre = size.toString().length; name = func.substr(i + pre, size); i += pre + size; } } first = false; if (func[i] === 'I') { i++; var iList = parse(true); var iRet = parse(true, 1, true); ret += iRet[0] + ' ' + name + '<' + iList.join(', ') + '>'; } else { ret = name; } paramLoop: while (i < func.length && limit-- > 0) { //dump('paramLoop'); var c = func[i++]; if (c in basicTypes) { list.push(basicTypes[c]); } else { switch (c) { case 'P': list.push(parse(true, 1, true)[0] + '*'); break; // pointer case 'R': list.push(parse(true, 1, true)[0] + '&'); break; // reference case 'L': { // literal i++; // skip basic type var end = func.indexOf('E', i); var size = end - i; list.push(func.substr(i, size)); i += size + 2; // size + 'EE' break; } case 'A': { // array var size = parseInt(func.substr(i)); i += size.toString().length; if (func[i] !== '_') throw '?'; i++; // skip _ list.push(parse(true, 1, true)[0] + ' [' + size + ']'); break; } case 'E': break paramLoop; default: ret += '?' + c; break paramLoop; } } } if (!allowVoid && list.length === 1 && list[0] === 'void') list = []; // avoid (void) if (rawList) { if (ret) { list.push(ret + '?'); } return list; } else { return ret + flushList(); } } try { // Special-case the entry point, since its name differs from other name mangling. if (func == 'Object._main' || func == '_main') { return 'main()'; } if (typeof func === 'number') func = Pointer_stringify(func); if (func[0] !== '_') return func; if (func[1] !== '_') return func; // C function if (func[2] !== 'Z') return func; switch (func[3]) { case 'n': return 'operator new()'; case 'd': return 'operator delete()'; } return parse(); } catch(e) { return func; } } function demangleAll(text) { return text.replace(/__Z[\w\d_]+/g, function(x) { var y = demangle(x); return x === y ? x : (x + ' [' + y + ']') }); } function stackTrace() { var stack = new Error().stack; return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6. } // Memory management var PAGE_SIZE = 4096; function alignMemoryPage(x) { return (x+4095)&-4096; } var HEAP; #if USE_TYPED_ARRAYS == 1 var IHEAP, IHEAPU; #if USE_FHEAP var FHEAP; #endif #endif #if USE_TYPED_ARRAYS == 2 var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; #endif var STATIC_BASE = 0, STATICTOP = 0, staticSealed = false; // static area var STACK_BASE = 0, STACKTOP = 0, STACK_MAX = 0; // stack area var DYNAMIC_BASE = 0, DYNAMICTOP = 0; // dynamic area handled by sbrk #if USE_TYPED_ARRAYS function enlargeMemory() { #if ALLOW_MEMORY_GROWTH == 0 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 ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.'); #else // TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top. #if ASSERTIONS Module.printErr('Warning: Enlarging memory arrays, this is not fast! ' + [DYNAMICTOP, TOTAL_MEMORY]); assert(DYNAMICTOP >= TOTAL_MEMORY); assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite #endif while (TOTAL_MEMORY <= DYNAMICTOP) { // Simple heuristic. TOTAL_MEMORY = alignMemoryPage(2*TOTAL_MEMORY); } assert(TOTAL_MEMORY <= Math.pow(2, 30)); // 2^30==1GB is a practical maximum - 2^31 is already close to possible negative numbers etc. #if USE_TYPED_ARRAYS == 2 var oldHEAP8 = HEAP8; var buffer = new ArrayBuffer(TOTAL_MEMORY); 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); HEAP8.set(oldHEAP8); #else abort('cannot enlarge memory arrays in non-ta2 modes'); #endif #if ASM_JS _emscripten_replace_memory(HEAP8, HEAP16, HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32, HEAPF64); #endif #endif } #endif var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}}; var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}}; #if ASM_JS var totalMemory = 4096; while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) { if (totalMemory < 16*1024*1024) { totalMemory *= 2; } else { totalMemory += 16*1024*1024 } } if (totalMemory !== TOTAL_MEMORY) { Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be more reasonable'); TOTAL_MEMORY = totalMemory; } #endif // Initialize the runtime's memory #if USE_TYPED_ARRAYS // check for full engine support (use string 'subarray' to avoid closure compiler confusion) assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']), 'JS engine does not provide full typed array support'); #if USE_TYPED_ARRAYS == 1 HEAP = IHEAP = new Int32Array(TOTAL_MEMORY); IHEAPU = new Uint32Array(IHEAP.buffer); #if USE_FHEAP FHEAP = new Float64Array(TOTAL_MEMORY); #endif #endif #if USE_TYPED_ARRAYS == 2 var buffer = new ArrayBuffer(TOTAL_MEMORY); HEAP8 = new Int8Array(buffer); HEAP16 = new Int16Array(buffer); HEAP32 = new Int32Array(buffer); HEAPU8 = new Uint8Array(buffer); HEAPU16 = new Uint16Array(buffer); HEAPU32 = new Uint32Array(buffer); HEAPF32 = new Float32Array(buffer); HEAPF64 = new Float64Array(buffer); // Endianness check (note: assumes compiler arch was little-endian) HEAP32[0] = 255; assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system'); #endif #else // Make sure that our HEAP is implemented as a flat array. HEAP = []; // Hinting at the size with |new Array(TOTAL_MEMORY)| should help in theory but makes v8 much slower for (var i = 0; i < FAST_MEMORY; i++) { HEAP[i] = 0; // XXX We do *not* use {{| makeSetValue(0, 'i', 0, 'null') |}} here, since this is done just to optimize runtime speed } #endif Module['HEAP'] = HEAP; #if USE_TYPED_ARRAYS == 1 Module['IHEAP'] = IHEAP; #if USE_FHEAP Module['FHEAP'] = FHEAP; #endif #endif #if USE_TYPED_ARRAYS == 2 Module['HEAP8'] = HEAP8; Module['HEAP16'] = HEAP16; Module['HEAP32'] = HEAP32; Module['HEAPU8'] = HEAPU8; Module['HEAPU16'] = HEAPU16; Module['HEAPU32'] = HEAPU32; Module['HEAPF32'] = HEAPF32; Module['HEAPF64'] = HEAPF64; #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) { Runtime.dynCall('v', func); } else { Runtime.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 runtime has exited var runtimeInitialized = false; function preRun() { // 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 (runtimeInitialized) return; runtimeInitialized = true; callRuntimeCallbacks(__ATINIT__); } function preMain() { callRuntimeCallbacks(__ATMAIN__); } function exitRuntime() { #if ASSERTIONS if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { Module.printErr('Exiting runtime. Any attempt to access the compiled C code may fail from now. If you want to keep the runtime alive, set Module["noExitRuntime"] = true or build with -s NO_EXIT_RUNTIME=1'); } #endif callRuntimeCallbacks(__ATEXIT__); } function postRun() { // 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); } Module['addOnPreRun'] = Module.addOnPreRun = addOnPreRun; function addOnInit(cb) { __ATINIT__.unshift(cb); } Module['addOnInit'] = Module.addOnInit = addOnInit; function addOnPreMain(cb) { __ATMAIN__.unshift(cb); } Module['addOnPreMain'] = Module.addOnPreMain = addOnPreMain; function addOnExit(cb) { __ATEXIT__.unshift(cb); } Module['addOnExit'] = Module.addOnExit = addOnExit; function addOnPostRun(cb) { __ATPOSTRUN__.unshift(cb); } Module['addOnPostRun'] = Module.addOnPostRun = addOnPostRun; // Tools // This processes a JS string into a C-line array of numbers, 0-terminated. // For LLVM-originating strings, see parser.js:parseLLVMString function function intArrayFromString(stringy, dontAddNull, length /* optional */) { var ret = (new Runtime.UTF8Processor()).processJSString(stringy); if (length) { ret.length = length; } if (!dontAddNull) { ret.push(0); } return ret; } Module['intArrayFromString'] = intArrayFromString; function intArrayToString(array) { var ret = []; for (var i = 0; i < array.length; i++) { var chr = array[i]; if (chr > 0xFF) { #if ASSERTIONS assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.'); #endif chr &= 0xFF; } ret.push(String.fromCharCode(chr)); } return ret.join(''); } Module['intArrayToString'] = intArrayToString; // Write a Javascript array to somewhere in the heap function writeStringToMemory(string, buffer, dontAddNull) { var array = intArrayFromString(string, dontAddNull); var i = 0; while (i < array.length) { var chr = array[i]; {{{ makeSetValue('buffer', 'i', 'chr', 'i8') }}}; i = i + 1; } } Module['writeStringToMemory'] = writeStringToMemory; function writeArrayToMemory(array, buffer) { for (var i = 0; i < array.length; i++) { {{{ makeSetValue('buffer', 'i', 'array[i]', 'i8') }}}; } } Module['writeArrayToMemory'] = writeArrayToMemory; 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', 'i', 'str.charCodeAt(i)', 'i8') }}}; } if (!dontAddNull) {{{ makeSetValue('buffer', 'str.length', 0, 'i8') }}}; } Module['writeAsciiToMemory'] = writeAsciiToMemory; {{{ unSign }}} {{{ reSign }}} #if PRECISE_I32_MUL // 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; }; #else Math['imul'] = function imul(a, b) { return (a*b)|0; // fast but imprecise }; #endif 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']; #endif 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_min = Math.min; // 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 addRunDependency(id) { 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() { 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 } Module['addRunDependency'] = addRunDependency; 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['removeRunDependency'] = removeRunDependency; Module["preloadedImages"] = {}; // maps url to image data Module["preloadedAudios"] = {}; // maps url to audio data #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({ func: function() { PGOMonitor.dump() } }); addOnPreRun(function() { addRunDependency('pgo') }); #endif var memoryInitializer = null; // === Body ===