// === Auto-generated preamble library stuff ===
//========================================
// Runtime code shared with compiler
//========================================
{{RUNTIME}}
#if SAFE_HEAP
//========================================
// Debugging tools - Heap
//========================================
var HEAP_WATCHED = [];
var HEAP_HISTORY = [];
function SAFE_HEAP_CLEAR(dest) {
#if SAFE_HEAP_LOG
print('SAFE_HEAP clear: ' + dest);
#endif
HEAP_HISTORY[dest] = [];
}
var SAFE_HEAP_ERRORS = 0;
var ACCEPTABLE_SAFE_HEAP_ERRORS = 0;
function SAFE_HEAP_ACCESS(dest, type, store, ignore) {
//if (dest === A_NUMBER) print ([dest, type, store] + ' ' + new Error().stack); // Something like this may be useful, in debugging
#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).
assert(dest < STATICTOP);
assert(STATICTOP <= 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[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 + ' :: ' + new Error().stack + '\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' + new Error().stack + '\n');
// if (history[0].type !== type) {
if (history !== type && !ignore) {
print('Load-store consistency assumption failure! ' + dest);
print('\n');
print(JSON.stringify(history));
print('\n');
print('LOAD: ' + type + ', ' + new Error().stack);
print('\n');
SAFE_HEAP_ERRORS++;
assert(SAFE_HEAP_ERRORS <= ACCEPTABLE_SAFE_HEAP_ERRORS, 'Load-store consistency assumption failure!');
}
}
}
#if USE_TYPED_ARRAYS == 2
var warned64 = false;
function warn64() {
if (!warned64) {
__ATEXIT__.push({ func: function() {
print('Warning: using a 64-bit type with USE_TYPED_ARRAYS == 2. Depending on I64_MODE this may be problematic.');
} });
warned64 = true;
}
}
#endif
function SAFE_HEAP_STORE(dest, value, type, ignore) {
#if SAFE_HEAP_LOG
print('SAFE_HEAP store: ' + [dest, type, value, ignore]);
#endif
if (!ignore && !value && value !== 0 && value !== false && !isNaN(value)) { // false can be the result of a mathop comparator; NaN can be the result of a math function
throw('Warning: Writing an invalid value of ' + JSON.stringify(value) + ' at ' + dest + ' :: ' + new Error().stack + '\n');
}
SAFE_HEAP_ACCESS(dest, type, true, ignore);
if (dest in HEAP_WATCHED) {
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); warn64(); break;
#endif
}
#endif
setValue(dest, value, type, 1);
}
function SAFE_HEAP_LOAD(dest, type, unsigned, ignore) {
SAFE_HEAP_ACCESS(dest, type, ignore);
#if SAFE_HEAP_LOG
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); warn64(); 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
print('SAFE_HEAP copy: ' + [dest, src]);
#endif
HEAP_HISTORY[dest] = HEAP_HISTORY[src];
SAFE_HEAP_ACCESS(dest, HEAP_HISTORY[dest] || null, true, false);
}
//==========================================
#endif
var CorrectionsMonitor = {
#if PGO
MAX_ALLOWED: Infinity,
#else
MAX_ALLOWED: 0, // XXX
#endif
corrections: 0,
sigs: {},
note: function(type, succeed, sig) {
if (!succeed) {
this.corrections++;
if (this.corrections >= this.MAX_ALLOWED) abort('\n\nToo many corrections!');
}
#if PGO
if (!sig)
sig = (new Error().stack).toString().split('\n')[2].split(':').slice(-1)[0]; // Spidermonkey-specific FIXME
sig = type + '|' + sig;
if (!this.sigs[sig]) {
//print('Correction: ' + sig);
this.sigs[sig] = [0, 0]; // fail, succeed
}
this.sigs[sig][succeed ? 1 : 0]++;
#endif
},
print: function() {
#if PGO
var items = [];
for (var sig in this.sigs) {
items.push({
sig: sig,
fails: this.sigs[sig][0],
succeeds: this.sigs[sig][1],
total: this.sigs[sig][0] + this.sigs[sig][1]
});
}
items.sort(function(x, y) { return y.total - x.total; });
for (var i = 0; i < items.length; i++) {
var item = items[i];
print(item.sig + ' : ' + item.total + ' hits, %' + (Math.ceil(100*item.fails/item.total)) + ' failures');
}
#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) {
CorrectionsMonitor.note('SignedOverflow', 0, sig);
if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) CorrectionsMonitor.note('Overflow');
#else
if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) {
CorrectionsMonitor.note('Overflow', 0, sig);
#endif
#if CORRECT_OVERFLOWS
// Fail on >32 bits - we warned at compile time
if (bits <= 32) {
value = value & (twopbits - 1);
}
#endif
} else {
#if CHECK_SIGNED_OVERFLOWS
CorrectionsMonitor.note('SignedOverflow', 1, sig);
#endif
CorrectionsMonitor.note('Overflow', 1, sig);
}
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
#if PROFILE
var PROFILING = 0;
var PROFILING_ROOT = { time: 0, children: {}, calls: 0 };
var PROFILING_NODE;
function startProfiling() {
PROFILING_NODE = PROFILING_ROOT;
PROFILING = 1;
}
Module['startProfiling'] = startProfiling;
function stopProfiling() {
PROFILING = 0;
assert(PROFILING_NODE === PROFILING_ROOT, 'Must have popped all the profiling call stack');
}
Module['stopProfiling'] = stopProfiling;
function printProfiling() {
function dumpData(name_, node, indent) {
print(indent + ('________' + node.time).substr(-8) + ': ' + name_ + ' (' + node.calls + ')');
var children = [];
for (var child in node.children) {
children.push(node.children[child]);
children[children.length-1].name_ = child;
}
children.sort(function(x, y) { return y.time - x.time });
children.forEach(function(child) { dumpData(child.name_, child, indent + ' ') });
}
dumpData('root', PROFILING_ROOT, ' ');
}
Module['printProfiling'] = printProfiling;
function printXULProfiling() {
function dumpData(name_, node, indent) {
var children = [];
for (var child in node.children) {
children.push(node.children[child]);
children[children.length-1].name_ = child;
}
print(' 0 ? ' container="true"' : '') + '>');
print(' ');
print(' ');
print(' ');
print(' ');
print(' ');
if (children.length > 0) {
print(' ');
children.sort(function(x, y) { return y.time - x.time });
children.forEach(function(child) { dumpData(child.name_, child, indent + ' ') });
print(' ');
}
print('');
}
print('');
print(' ');
print(' ');
print(' ');
print('');
print(' ');
print(' ');
print(' ');
print(' ');
print(' ');
print(' ');
print(' ');
dumpData('root', PROFILING_ROOT, ' ');
print(' ');
print('');
print('');
// This requires dom.allow_XUL_XBL_for_file
}
Module['printXULProfiling'] = printXULProfiling;
#endif
//========================================
// Runtime essentials
//========================================
var __THREW__ = false; // Used in checking for thrown exceptions.
var ABORT = false;
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;
#if I64_MODE == 1
var tempI64, tempI64b;
#endif
#if DOUBLE_MODE == 1
#if USE_TYPED_ARRAYS == 2
var tempDoubleBuffer = new ArrayBuffer(8);
var tempDoubleI32 = new Int32Array(tempDoubleBuffer);
var tempDoubleF64 = new Float64Array(tempDoubleBuffer);
#endif
#endif
function abort(text) {
print(text + ':\n' + (new Error).stack);
ABORT = true;
throw "Assertion: " + text;
}
function assert(condition, text) {
if (!condition) {
abort('Assertion failed: ' + text);
}
}
// 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.
function setValue(ptr, value, type, noSafe) {
type = type || 'i8';
if (type[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[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;
// Allocates memory for some data and initializes it properly.
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
Module['ALLOC_NORMAL'] = ALLOC_NORMAL;
Module['ALLOC_STACK'] = ALLOC_STACK;
Module['ALLOC_STATIC'] = ALLOC_STATIC;
function allocate(slab, types, allocator) {
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 = [_malloc, Runtime.stackAlloc, Runtime.staticAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));
if (zeroinit) {
_memset(ret, 0, size);
return ret;
}
var i = 0, type;
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 I64_MODE == 1
if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
#endif
setValue(ret+i, curr, type);
i += Runtime.getNativeTypeSize(type);
}
return ret;
}
Module['allocate'] = allocate;
function Pointer_stringify(ptr, /* optional */ length) {
var nullTerminated = typeof(length) == "undefined";
var ret = "";
var i = 0;
var t;
var nullByte = String.fromCharCode(0);
while (1) {
t = String.fromCharCode({{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}});
if (nullTerminated && t == nullByte) { break; } else {}
ret += t;
i += 1;
if (!nullTerminated && i == length) { break; }
}
return ret;
}
Module['Pointer_stringify'] = Pointer_stringify;
function Array_stringify(array) {
var ret = "";
for (var i = 0; i < array.length; i++) {
ret += String.fromCharCode(array[i]);
}
return ret;
}
Module['Array_stringify'] = Array_stringify;
// Memory management
var FUNCTION_TABLE; // XXX: In theory the indexes here can be equal to pointers to stacked or malloced memory. Such comparisons should
// be false, but can turn out true. We should probably set the top bit to prevent such issues.
var PAGE_SIZE = 4096;
function alignMemoryPage(x) {
return Math.ceil(x/PAGE_SIZE)*PAGE_SIZE;
}
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;
#endif
var STACK_ROOT, STACKTOP, STACK_MAX;
var STATICTOP;
#if USE_TYPED_ARRAYS
function enlargeMemory() {
// TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top.
#if ASSERTIONS
printErr('Warning: Enlarging memory arrays, this is not fast! ' + [STATICTOP, TOTAL_MEMORY]);
assert(STATICTOP >= TOTAL_MEMORY);
assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite
#endif
while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it
TOTAL_MEMORY = alignMemoryPage(2*TOTAL_MEMORY);
}
#if USE_TYPED_ARRAYS == 1
var oldIHEAP = IHEAP;
HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
IHEAP.set(oldIHEAP);
IHEAPU = new Uint32Array(IHEAP.buffer);
#if USE_FHEAP
var oldFHEAP = FHEAP;
FHEAP = new Float64Array(TOTAL_MEMORY);
FHEAP.set(oldFHEAP);
#endif
#endif
#if USE_TYPED_ARRAYS == 2
var oldHEAP8 = HEAP8;
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);
HEAP8.set(oldHEAP8);
#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 }}};
// Initialize the runtime's memory
#if USE_TYPED_ARRAYS
// check for full engine support (use string 'subarray' to avoid closure compiler confusion)
assert(!!Int32Array && !!Float64Array && !!(new Int32Array(1)['subarray']) && !!(new Int32Array(1)['set']),
'Cannot fallback to non-typed array case: Code is too specialized');
#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);
// 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 = new Array(TOTAL_MEMORY);
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
var base = intArrayFromString('(null)'); // So printing %s of NULL gives '(null)'
// Also this ensures we leave 0 as an invalid address, 'NULL'
STATICTOP = base.length;
for (var i = 0; i < base.length; i++) {
{{{ makeSetValue(0, 'i', 'base[i]', 'i8') }}}
}
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;
#endif
STACK_ROOT = STACKTOP = Runtime.alignMemory(STATICTOP);
STACK_MAX = STACK_ROOT + TOTAL_STACK;
STATICTOP = alignMemoryPage(STACK_MAX);
function callRuntimeCallbacks(callbacks) {
while(callbacks.length > 0) {
var callback = callbacks.pop();
var func = callback.func;
if (typeof func === 'number') {
func = FUNCTION_TABLE[func];
}
func(callback.arg === undefined ? null : callback.arg);
}
}
var __ATINIT__ = []; // functions called during startup
var __ATEXIT__ = []; // functions called during shutdown
function initRuntime() {
callRuntimeCallbacks(__ATINIT__);
}
function exitRuntime() {
callRuntimeCallbacks(__ATEXIT__);
// Print summary of correction activity
CorrectionsMonitor.print();
}
// Copies a list of num items on the HEAP into a
// a normal JavaScript array of numbers
function Array_copy(ptr, num) {
#if USE_TYPED_ARRAYS == 1
// TODO: In the SAFE_HEAP case, do some reading here, for debugging purposes - currently this is an 'unnoticed read'.
return Array.prototype.slice.call(IHEAP.subarray(ptr, ptr+num)); // Make a normal array out of the typed 'view'
// Consider making a typed array here, for speed?
#endif
#if USE_TYPED_ARRAYS == 2
return Array.prototype.slice.call(HEAP8.subarray(ptr, ptr+num)); // Make a normal array out of the typed 'view'
// Consider making a typed array here, for speed?
#endif
return HEAP.slice(ptr, ptr+num);
}
Module['Array_copy'] = Array_copy;
#if USE_TYPED_ARRAYS
// Copies a list of num items on the HEAP into a
// JavaScript typed array.
function TypedArray_copy(ptr, num) {
// TODO: optimize this!
var arr = new Uint8Array(num);
for (var i = 0; i < num; ++i) {
arr[i] = {{{ makeGetValue('ptr', 'i', 'i8') }}};
}
return arr.buffer;
}
Module['TypedArray_copy'] = TypedArray_copy;
#endif
function String_len(ptr) {
var i = 0;
while ({{{ makeGetValue('ptr', 'i', 'i8') }}}) i++; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
return i;
}
Module['String_len'] = String_len;
// Copies a C-style string, terminated by a zero, from the HEAP into
// a normal JavaScript array of numbers
function String_copy(ptr, addZero) {
var len = String_len(ptr);
if (addZero) len++;
var ret = Array_copy(ptr, len);
if (addZero) ret[len-1] = 0;
return ret;
}
Module['String_copy'] = String_copy;
// 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) {
var ret = [];
var t;
var i = 0;
while (i < stringy.length) {
var chr = stringy.charCodeAt(i);
if (chr > 0xFF) {
#if ASSERTIONS
assert(false, 'Character code ' + chr + ' (' + stringy[i] + ') at offset ' + i + ' not in 0x00-0xFF.');
#endif
chr &= 0xFF;
}
ret.push(chr);
i = i + 1;
}
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 i = 0;
while (i < string.length) {
var chr = string.charCodeAt(i);
if (chr > 0xFF) {
#if ASSERTIONS
assert(false, 'Character code ' + chr + ' (' + string[i] + ') at offset ' + i + ' not in 0x00-0xFF.');
#endif
chr &= 0xFF;
}
{{{ makeSetValue('buffer', 'i', 'chr', 'i8') }}}
i = i + 1;
}
if (!dontAddNull) {
{{{ makeSetValue('buffer', 'i', '0', 'i8') }}}
}
}
var STRING_TABLE = [];
{{{ unSign }}}
{{{ reSign }}}
// === Body ===