aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2011-12-10 17:26:15 -0800
committerAlon Zakai <alonzakai@gmail.com>2011-12-10 17:26:15 -0800
commitf59ffc338e2c1df792709a823be1c1d2735e88bf (patch)
tree7268bc264e4364f9766f1b137882870bf7b90569 /src
parent0162cc4bdc1955b442bec1a185d024d3d30cec0e (diff)
parent3a35fd9389a18707abd51dc71e2096c64413d510 (diff)
Merge branch 'ta2bydefault'
Diffstat (limited to 'src')
-rw-r--r--src/intertyper.js9
-rw-r--r--src/jsifier.js6
-rw-r--r--src/library.js65
-rw-r--r--src/modules.js31
-rw-r--r--src/parseTools.js107
-rw-r--r--src/preamble.js221
-rw-r--r--src/runtime.js8
-rw-r--r--src/settings.js30
8 files changed, 308 insertions, 169 deletions
diff --git a/src/intertyper.js b/src/intertyper.js
index 19eb658e..f3d68ac4 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -123,6 +123,12 @@ function intertyper(data, sidePass, baseLineNums) {
inFunction = false;
if (mainPass) {
var func = funcHeader.processItem(tokenizer.processItem({ lineText: currFunctionLines[0], lineNum: currFunctionLineNum }, true))[0];
+
+ if (SKIP_STACK_IN_SMALL && /emscripten_autodebug/.exec(func.ident)) {
+ warn('Disabling SKIP_STACK_IN_SMALL because we are apparently processing autodebugger data');
+ SKIP_STACK_IN_SMALL = 0;
+ }
+
unparsedBundles.push({
intertype: 'unparsedFunction',
// We need this early, to know basic function info - ident, params, varargs
@@ -797,6 +803,9 @@ function intertyper(data, sidePass, baseLineNums) {
var segments = splitTokenList(item.tokens.slice(1));
for (var i = 1; i <= 4; i++) {
if (segments[i-1]) {
+ if (i > 1 && segments[i-1].length == 1 && segments[0].length > 1) {
+ segments[i-1].unshift(segments[0][0]); // Add the type from the first segment, they are all alike
+ }
item['param'+i] = parseLLVMSegment(segments[i-1]);
}
}
diff --git a/src/jsifier.js b/src/jsifier.js
index a2ca03eb..b02164f6 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -341,7 +341,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var ret = [item];
item.JS = 'var ' + item.ident + ';';
// Set the actual value in a postset, since it may be a global variable. We also order by dependencies there
- var value = finalizeLLVMParameter(item.value, true); // do *not* indexize functions here
+ var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value);
ret.push({
intertype: 'GlobalVariablePostSet',
ident: item.ident,
@@ -632,10 +632,6 @@ function JSify(data, functionsOnly, givenFunctions) {
var local = funcData.variables[ident];
if (local) return local;
var global = Variables.globals[ident];
- // FIXME: Currently, if something is an alias, we assume it is not a simple variable, so no need for
- // FUNCTION_TABLE when calling it (which we do need for a normal simple global variable). In
- // theory though an alias could be simple, we should probably check the type if this ever becomes a problem.
- if (global && global.alias) global = null;
return global || null;
}
diff --git a/src/library.js b/src/library.js
index 1d296981..e1121c2f 100644
--- a/src/library.js
+++ b/src/library.js
@@ -706,9 +706,8 @@ LibraryManager.library = {
mode = obj.link === undefined ? 0x8000 : 0xA000; // S_IFREG, S_IFLNK.
}
}
- {{{ makeSetValue('buf', 'offsets.st_dev', makeI64('dev'), 'i64') }}};
- {{{ makeSetValue('buf', 'offsets.st_rdev', makeI64('rdev'), 'i64') }}};
- // NOTE: These two may be i64, depending on compilation options.
+ {{{ makeSetValue('buf', 'offsets.st_dev', 'dev', 'i32') }}};
+ {{{ makeSetValue('buf', 'offsets.st_rdev', 'rdev', 'i32') }}};
{{{ makeSetValue('buf', 'offsets.st_size', 'size', 'i32') }}}
{{{ makeSetValue('buf', 'offsets.st_blocks', 'blocks', 'i32') }}}
if (obj.read) mode |= 0x16D; // S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH.
@@ -3841,9 +3840,57 @@ LibraryManager.library = {
return 0;
},
- // Compiled from newlib; for the original source and licensing, see library_strtok_r.c XXX will not work with typed arrays
- strtok_r: function(b,j,f){var a;a=null;var c,e;b=b;var i=b!=0;a:do if(i)a=0;else{b=HEAP[f];if(b!=0){a=0;break a}c=0;a=3;break a}while(0);if(a==0){a:for(;;){e=HEAP[b];b+=1;a=j;var g=e;i=a;a=2;b:for(;;){d=a==5?d:0;a=HEAP[i+d];if(a!=0==0){a=9;break a}var d=d+1;if(g==a)break b;else a=5}a=2}if(a==9)if(g==0)c=HEAP[f]=0;else{c=b+-1;a:for(;;){e=HEAP[b];b+=1;a=j;g=e;d=a;a=10;b:for(;;){h=a==13?h:0;a=HEAP[d+h];if(a==g!=0)break a;var h=h+1;if(a!=0)a=13;else break b}}if(e==0)b=0;else HEAP[b+-1]=0; HEAP[f]=b;c=c}else if(a==7){HEAP[f]=b;HEAP[b+-1]=0;c=b+-1}}return c},
- // TODO: Compile strtok() from source.
+ // Translated from newlib; for the original source and licensing, see library_strtok_r.c
+ strtok_r: function(s, delim, lasts) {
+ var skip_leading_delim = 1;
+ var spanp;
+ var c, sc;
+ var tok;
+
+
+ if (s == 0 && (s = getValue(lasts, 'i8*')) == 0) {
+ return 0;
+ }
+
+ cont: while (1) {
+ c = getValue(s++, 'i8');
+ for (spanp = delim; (sc = getValue(spanp++, 'i8')) != 0;) {
+ if (c == sc) {
+ if (skip_leading_delim) {
+ continue cont;
+ } else {
+ setValue(lasts, s, 'i8*');
+ setValue(s - 1, 0, 'i8');
+ return s - 1;
+ }
+ }
+ }
+ break;
+ }
+
+ if (c == 0) {
+ setValue(lasts, 0, 'i8*');
+ return 0;
+ }
+ tok = s - 1;
+
+ for (;;) {
+ c = getValue(s++, 'i8');
+ spanp = delim;
+ do {
+ if ((sc = getValue(spanp++, 'i8')) == c) {
+ if (c == 0) {
+ s = 0;
+ } else {
+ setValue(s - 1, 0, 'i8');
+ }
+ setValue(lasts, s, 'i8*');
+ return tok;
+ }
+ } while (sc != 0);
+ }
+ abort('strtok_r error!');
+ },
strerror_r__deps: ['$ERRNO_CODES', '$ERRNO_MESSAGES', '__setErrNo'],
strerror_r: function(errnum, strerrbuf, buflen) {
@@ -5057,7 +5104,7 @@ LibraryManager.library = {
// var indexes = Runtime.calculateStructAlignment({ fields: ['i32', 'i32'] });
var me = _localeconv;
if (!me.ret) {
- me.ret = allocate([allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL)], 'i8', ALLOC_NORMAL); // just decimal point, for now
+ me.ret = allocate([allocate(intArrayFromString('.'), 'i8', ALLOC_NORMAL)], 'i8*', ALLOC_NORMAL); // just decimal point, for now
}
return me.ret;
},
@@ -5493,8 +5540,8 @@ LibraryManager.library = {
eval(Pointer_stringify(ptr));
},
- _Z21emscripten_run_scriptPKc: function(ptr) {
- eval(Pointer_stringify(ptr));
+ emscripten_run_script_int: function(ptr) {
+ return eval(Pointer_stringify(ptr));
},
$Profiling: {
diff --git a/src/modules.js b/src/modules.js
index 3ce4a541..49f93e61 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -254,22 +254,37 @@ var Functions = {
// All the function idents seen so far
allIdents: [],
- indexedFunctions: [0, 0], // Start at a non-0 (even, see below) value
+ indexedFunctions: {},
+ nextIndex: 2, // Start at a non-0 (even, see below) value
// Mark a function as needing indexing, and returns the index
getIndex: function(ident) {
- var key = this.indexedFunctions.indexOf(ident);
- if (key < 0) {
- key = this.indexedFunctions.length;
- this.indexedFunctions[key] = ident;
- this.indexedFunctions[key+1] = 0; // Need to have keys be even numbers, see |polymorph| test
+ var ret = this.indexedFunctions[ident];
+ if (!ret) {
+ ret = this.nextIndex;
+ this.nextIndex += 2; // Need to have indexes be even numbers, see |polymorph| test
+ this.indexedFunctions[ident] = ret;
}
- return key.toString();
+ return ret.toString();
},
// Generate code for function indexing
generateIndexing: function() {
- var indices = this.indexedFunctions.toString().replace('"', '');
+ var vals = zeros(this.nextIndex);
+ for (var ident in this.indexedFunctions) {
+ vals[this.indexedFunctions[ident]] = ident;
+ }
+
+ // Resolve multi-level aliases all the way down
+ for (var i = 0; i < vals.length; i++) {
+ while (1) {
+ var varData = Variables.globals[vals[i]];
+ if (!(varData && varData.resolvedAlias)) break;
+ vals[i] = vals[varData.resolvedAlias];
+ }
+ }
+
+ var indices = vals.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the parent's function table.
return 'FUNCTION_TABLE = FUNCTION_TABLE.concat([' + indices + ']);';
diff --git a/src/parseTools.js b/src/parseTools.js
index 3eaf3577..024026c8 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -95,9 +95,9 @@ function toNiceIdentCarefully(ident) {
// is true, then also allow () and spaces.
function isNiceIdent(ident, loose) {
if (loose) {
- return /^[\w$_ ()]+$/.test(ident);
+ return /^\(?[$_]+[\w$_\d ]*\)?$/.test(ident);
} else {
- return /^[\w$_]+$/.test(ident);
+ return /^[$_]+[\w$_\d]*$/.test(ident);
}
}
@@ -559,17 +559,23 @@ function makeInlineCalculation(expression, value, tempVar) {
return '(' + expression.replace(/VALUE/g, value) + ')';
}
-// Makes a proper runtime value for a 64-bit value from low and high i32s.
+// Given two 32-bit unsigned parts of an emulated 64-bit number, combine them into a JS number (double).
+// Rounding is inevitable if the number is large. This is a particular problem for small negative numbers
+// (-1 will be rounded!), so handle negatives separately and carefully
+function makeBigInt(low, high) {
+ // here VALUE will be the big part
+ return '(' + high + ' <= 2147483648 ? (' + makeSignOp(low, 'i32', 'un', 1, 1) + '+(' + makeSignOp(high, 'i32', 'un', 1, 1) + '*4294967296))' +
+ ' : (' + makeSignOp(low, 'i32', 're', 1, 1) + '+(1+' + makeSignOp(high, 'i32', 're', 1, 1) + ')*4294967296))';
+}
+
+// Makes a proper runtime value for a 64-bit value from low and high i32s. low and high are assumed to be unsigned.
function makeI64(low, high) {
+ high = high || '0';
if (I64_MODE == 1) {
- return '[' + low + ',' + (high || '0') + ']';
- // FIXME with this? return '[unSign(' + low + ',32),' + (high ? ('unSign(' + high + ',32)') : '0') + ']';
+ return '[' + makeSignOp(low, 'i32', 'un', 1, 1) + ',' + makeSignOp(high, 'i32', 'un', 1, 1) + ']';
} else {
- var ret = low;
- if (high) {
- ret = '(' + low + '+(4294967296*' + high + '))';
- }
- return ret;
+ if (high) return makeBigInt(low, high);
+ return low;
}
}
@@ -577,24 +583,25 @@ function makeI64(low, high) {
// Will suffer from rounding. margeI64 does the opposite.
// TODO: optimize I64 calcs. For example, saving their parts as signed 32 as opposed to unsigned would help
function splitI64(value) {
- assert(I64_MODE == 1);
- return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.floor(VALUE/4294967296)'), value, 'tempBigInt');
+ // We need to min here, since our input might be a double, and large values are rounded, so they can
+ // be slightly higher than expected. And if we get 4294967296, that will turn into a 0 if put into a
+ // HEAP32 or |0'd, etc.
+ return makeInlineCalculation(makeI64('VALUE>>>0', 'Math.min(Math.floor(VALUE/4294967296), 4294967295)'), value, 'tempBigIntP');
}
function mergeI64(value) {
assert(I64_MODE == 1);
- return '(tempI64=' + value + ',tempI64[0]+tempI64[1]*4294967296)';
+ return makeInlineCalculation(makeBigInt('VALUE[0]', 'VALUE[1]'), value, 'tempI64');
}
// Takes an i64 value and changes it into the [low, high] form used in i64 mode 1. In that
// mode, this is a no-op
function ensureI64_1(value) {
if (I64_MODE == 1) return value;
- return makeInlineCalculation('[VALUE>>>0, Math.floor(VALUE/4294967296)]', value, 'tempBigInt');
+ return splitI64(value, 1);
}
function makeCopyI64(value) {
assert(I64_MODE == 1);
-
return value + '.slice(0)';
}
@@ -889,7 +896,7 @@ function getHeapOffset(offset, type) {
}
// See makeSetValue
-function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
+function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSafe) {
if (isStructType(type)) {
var typeData = Types.types[type];
var ret = [];
@@ -899,6 +906,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
return '{ ' + ret.join(', ') + ' }';
}
+ if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
+ return '(tempDoubleI32[0]=' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ 'tempDoubleI32[1]=' + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore, align) + ',' +
+ 'tempDoubleF64[0])';
+ }
+
if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats
// Alignment is important here. May need to split this up
var bytes = Runtime.getNativeTypeSize(type);
@@ -923,12 +936,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
}
if (type == 'i64' && I64_MODE == 1) {
- return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, unsigned, ignore) + ','
- + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, unsigned, ignore) + ']';
+ return '[' + makeGetValue(ptr, pos, 'i32', noNeedFirst, 1, ignore) + ','
+ + makeGetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'i32', noNeedFirst, 1, ignore) + ']';
}
var offset = calcFastOffset(ptr, pos, noNeedFirst);
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !noSafe) {
if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"';
if (type[0] === '#') type = type.substr(1);
return 'SAFE_HEAP_LOAD(' + offset + ', ' + type + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
@@ -938,8 +951,8 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) {
}
function indexizeFunctions(value, type) {
- assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing: ' + [value, type]);
- assert(value !== type, 'Type set to value: ' + [value, type]);
+ assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing');
+ assert(value !== type, 'Type set to value');
if (type && isFunctionType(type) && value[0] === '_') { // checking for _ differentiates from $ (local vars)
if (BUILD_AS_SHARED_LIB) {
return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')';
@@ -960,7 +973,7 @@ function indexizeFunctions(value, type) {
//! 'null' means, in the context of SAFE_HEAP, that we should accept all types;
//! which means we should write to all slabs, ignore type differences if any on reads, etc.
//! @param noNeedFirst Whether to ignore the offset in the pointer itself.
-function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
+function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe) {
if (isStructType(type)) {
var typeData = Types.types[type];
var ret = [];
@@ -975,6 +988,12 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
return ret.join('; ');
}
+ if (DOUBLE_MODE == 1 && USE_TYPED_ARRAYS == 2 && type == 'double') {
+ return '(tempDoubleF64[0]=' + value + ',' +
+ makeSetValue(ptr, pos, 'tempDoubleI32[0]', 'i32', noNeedFirst, ignore, align) + ',' +
+ makeSetValue(ptr, getFastValue(pos, '+', Runtime.getNativeTypeSize('i32')), 'tempDoubleI32[1]', 'i32', noNeedFirst, ignore, align) + ')';
+ }
+
if (EMULATE_UNALIGNED_ACCESSES && USE_TYPED_ARRAYS == 2 && align && isIntImplemented(type)) { // TODO: support unaligned doubles and floats
// Alignment is important here. May need to split this up
var bytes = Runtime.getNativeTypeSize(type);
@@ -1003,7 +1022,7 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align) {
value = indexizeFunctions(value, type);
var offset = calcFastOffset(ptr, pos, noNeedFirst);
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !noSafe) {
if (type !== 'null' && type[0] !== '#') type = '"' + safeQuote(type) + '"';
if (type[0] === '#') type = type.substr(1);
return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + type + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
@@ -1219,7 +1238,7 @@ function makeGetPos(ptr) {
return ptr;
}
-var IHEAP_FHEAP = set('IHEAP', 'FHEAP');
+var IHEAP_FHEAP = set('IHEAP', 'IHEAPU', 'FHEAP');
function makePointer(slab, pos, allocator, type) {
assert(type, 'makePointer requires type info');
@@ -1259,7 +1278,7 @@ function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
if (type in Runtime.FLOAT_TYPES || type === 'int64') { // XXX should be i64, no?
return ['FHEAP']; // If USE_FHEAP is false, will fail at runtime. At compiletime we do need it for library stuff.
} else if (type in Runtime.INT_TYPES || isPointerType(type)) {
- return ['IHEAP'];
+ return [unsigned ? 'IHEAPU' : 'IHEAP'];
} else {
assert(allowMultiple, 'Unknown slab type and !allowMultiple: ' + type);
if (USE_FHEAP) {
@@ -1320,10 +1339,7 @@ function finalizeLLVMFunctionCall(item, noIndexizeFunctions) {
// from one file to another, would be enough to fix this), or, do not pass structs by value (which in general
// is inefficient, and worth avoiding if you can).
}
- case 'inttoptr':
- case 'ptrtoint':
- return finalizeLLVMParameter(item.params[0], noIndexizeFunctions);
- case 'icmp': case 'mul': case 'zext': case 'add': case 'sub': case 'div':
+ case 'icmp': case 'mul': case 'zext': case 'add': case 'sub': case 'div': case 'inttoptr': case 'ptrtoint':
var temp = {
op: item.intertype,
variant: item.variant,
@@ -1457,10 +1473,9 @@ function finalizeLLVMParameter(param, noIndexizeFunctions) {
return ret;
}
-function makeSignOp(value, type, op, force) {
- // XXX this is not quite right. both parts should always be unsigned (or, perhaps always signed, we should move to that - separate issue though)
+function makeSignOp(value, type, op, force, ignore) {
if (I64_MODE == 1 && type == 'i64') {
- return '(tempPair=' + value + ',[' + makeSignOp('tempPair[0]', 'i32', op, force) + ',' + makeSignOp('tempPair[1]', 'i32', op, force) + '])';
+ return value; // these are always assumed to be two 32-bit unsigneds.
}
if (isPointerType(type)) type = 'i32'; // Pointers are treated as 32-bit ints
@@ -1469,7 +1484,7 @@ function makeSignOp(value, type, op, force) {
if (type in Runtime.INT_TYPES) {
bits = parseInt(type.substr(1));
full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(correctSpecificSign() && !PGO) + (
- PGO ? ', "' + Debugging.getIdentifier() + '"' : ''
+ PGO ? ', "' + (ignore ? '' : Debugging.getIdentifier()) + '"' : ''
) + ')';
// Always sign/unsign constants at compile time, regardless of CHECK/CORRECT
if (isNumber(value)) {
@@ -1479,7 +1494,7 @@ function makeSignOp(value, type, op, force) {
if (!correctSigns() && !CHECK_SIGNS && !force) return value;
if (type in Runtime.INT_TYPES) {
// shortcuts
- if (!CHECK_SIGNS) {
+ if (!CHECK_SIGNS || ignore) {
if (bits === 32) {
if (op === 're') {
return '((' + value + ')|0)';
@@ -1497,9 +1512,9 @@ function makeSignOp(value, type, op, force) {
}
} else { // bits > 32
if (op === 're') {
- return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigInt');
+ return makeInlineCalculation('VALUE >= ' + Math.pow(2, bits-1) + ' ? VALUE-' + Math.pow(2, bits) + ' : VALUE', value, 'tempBigIntS');
} else {
- return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigInt');
+ return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + '+VALUE', value, 'tempBigIntS');
}
}
}
@@ -1524,7 +1539,7 @@ function makeRounding(value, bits, signed, floatConversion) {
// Note that if converting a float, we may have the wrong sign at this point! But, we have
// been rounded properly regardless, and we will be sign-corrected later when actually used, if
// necessary.
- return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigInt');
+ return makeInlineCalculation('VALUE >= 0 ? Math.floor(VALUE) : Math.ceil(VALUE)', value, 'tempBigIntR');
}
// fptoui and fptosi are not in these, because we need to be careful about what we do there. We can't
@@ -1571,10 +1586,10 @@ function processMathop(item) {
if (item.type[0] === 'i') {
bits = parseInt(item.type.substr(1));
}
- var bitsLeft = ident2 ? ident2.substr(2, ident2.length-3) : null; // remove (i and ), to leave number. This value is important in float ops
+ var bitsLeft = item.param2 ? item.param2.ident.substr(1) : null; // remove i to leave number. This value is important in float ops
function integerizeBignum(value) {
- return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigInt');
+ return makeInlineCalculation('VALUE-VALUE%1', value, 'tempBigIntI');
}
if ((type == 'i64' || paramTypes[0] == 'i64' || paramTypes[1] == 'i64' || ident2 == '(i64)') && I64_MODE == 1) {
@@ -1594,14 +1609,14 @@ function processMathop(item) {
}
case 'shl': {
return '[' + ident1 + '[0] << ' + ident2 + ', ' +
- '('+ident1 + '[1] << ' + ident2 + ') | ((' + ident1 + '[0]&((Math.pow(2, ' + ident2 + ')-1)<<(32-' + ident2 + '))) >> (32-' + ident2 + '))]';
+ '('+ident1 + '[1] << ' + ident2 + ') | ((' + ident1 + '[0]&((Math.pow(2, ' + ident2 + ')-1)<<(32-' + ident2 + '))) >>> (32-' + ident2 + '))]';
}
case 'ashr': {
- return '[('+ident1 + '[0] >> ' + ident2 + ') | ((' + ident1 + '[1]&((Math.pow(2, ' + ident2 + ')-1)<<(32-' + ident2 + '))) >> (32-' + ident2 + ')),' +
- ident1 + '[1] >> ' + ident2 + ']';
+ return '[('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&(Math.pow(2, ' + ident2 + ')-1))<<(32-' + ident2 + ')),' +
+ ident1 + '[1] >>> ' + ident2 + ']';
}
case 'lshr': {
- return '[('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&((Math.pow(2, ' + ident2 + ')-1)<<(32-' + ident2 + '))) >> (32-' + ident2 + ')),' +
+ return '[('+ident1 + '[0] >>> ' + ident2 + ') | ((' + ident1 + '[1]&(Math.pow(2, ' + ident2 + ')-1))<<(32-' + ident2 + ')),' +
ident1 + '[1] >>> ' + ident2 + ']';
}
case 'uitofp': case 'sitofp': return ident1 + '[0] + ' + ident1 + '[1]*4294967296';
@@ -1632,12 +1647,13 @@ function processMathop(item) {
}
}
case 'zext': return makeI64(ident1, 0);
- case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), ident1, 'tempBigInt');
+ case 'sext': return makeInlineCalculation(makeI64('VALUE', 'VALUE<0 ? 4294967295 : 0'), ident1, 'tempBigIntD');
case 'trunc': {
return '((' + ident1 + '[0]) & ' + (Math.pow(2, bitsLeft)-1) + ')';
}
case 'select': return ident1 + ' ? ' + makeCopyI64(ident2) + ' : ' + makeCopyI64(ident3);
- case 'ptrtoint': case 'inttoptr': throw 'Pointers cannot be 64-bit!';
+ case 'ptrtoint': throw 'Pointers cannot be 64-bit!';
+ case 'inttoptr': return '(' + ident1 + '[0])'; // just directly truncate the i64 to a 'pointer', which is an i32
// Dangerous, rounded operations. TODO: Fully emulate
case 'add': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '+' + mergeI64(ident2)), bits);
case 'sub': warnI64_1(); return handleOverflow(splitI64(mergeI64(ident1) + '-' + mergeI64(ident2)), bits);
@@ -1772,6 +1788,7 @@ function processMathop(item) {
}
return ident1 + ret;
}
+ case 'bitcast': return ident1;
default: throw 'Unknown mathcmp op: ' + item.op;
}
}
diff --git a/src/preamble.js b/src/preamble.js
index 3fcdf1f8..a6556095 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -86,93 +86,50 @@ function SAFE_HEAP_STORE(dest, value, type, ignore) {
print((new Error()).stack);
throw "Bad store!" + dest;
}
-#if USE_TYPED_ARRAYS == 1
- if (type === null) {
- IHEAP[dest] = value;
-#if USE_FHEAP
- FHEAP[dest] = value;
-#endif
- } else if (type in Runtime.FLOAT_TYPES) {
- FHEAP[dest] = value;
- } else {
- IHEAP[dest] = value;
- }
-#else
+
#if USE_TYPED_ARRAYS == 2
- assert(type != 'null', 'typed arrays 2 with null type!');
- if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
+ // Check alignment
switch(type) {
- case 'i1': case 'i8': HEAP8[dest] = value; break;
- case 'i16': assert(dest % 2 === 0, type + ' stores must be aligned: ' + dest); HEAP16[dest>>1] = value; break;
- case 'i32': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAP32[dest>>2] = value; break;
- case 'i64': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAP32[dest>>2] = value; break; // XXX store int64 as int32
- case 'float': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); HEAPF32[dest>>2] = value; break;
- case 'double': assert(dest % 4 === 0, type + ' stores must be aligned: ' + dest); warn64(); HEAPF32[dest>>2] = value; break; // XXX store doubles as floats
- default: throw 'weird type for typed array II: ' + type + new Error().stack;
- }
+ 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
- HEAP[dest] = value;
+ 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 USE_TYPED_ARRAYS == 1
- if (type in Runtime.FLOAT_TYPES) {
#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, FHEAP[dest], ignore]);
+ print('SAFE_HEAP load: ' + [dest, type, getValue(dest, type, 1), ignore]);
#endif
- return FHEAP[dest];
- } else {
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, IHEAP[dest], ignore]);
-#endif
- return IHEAP[dest];
- }
-#else
+
#if USE_TYPED_ARRAYS == 2
-#if SAFE_HEAP_LOG
- var originalType = type;
-#endif
- var ret;
- if (type[type.length-1] === '*') type = 'i32'; // hardcoded pointers as 32-bit
+ // Check alignment
switch(type) {
- case 'i1': case 'i8': {
- ret = (unsigned ? HEAPU8 : HEAP8)[dest];
- break;
- }
- case 'i16': {
- assert(dest % 2 === 0, type + ' loads must be aligned: ' + dest);
- ret = (unsigned ? HEAPU16 : HEAP16)[dest>>1];
- break;
- }
- case 'i32': case 'i64': { // XXX store int64 as int32
- assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
- if (type === 'i64') warn64();
- ret = (unsigned ? HEAPU32 : HEAP32)[dest>>2];
- break;
- }
- case 'float': case 'double': { // XXX store doubles as floats
- assert(dest % 4 === 0, type + ' loads must be aligned: ' + dest);
- if (type === 'double') warn64();
- ret = HEAPF32[dest>>2];
- break;
- }
- default: throw 'weird type for typed array II: ' + type;
- }
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, originalType, ret, unsigned, ignore]);
-#endif
- return ret;
+ 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
-#if SAFE_HEAP_LOG
- print('SAFE_HEAP load: ' + [dest, type, HEAP[dest], ignore]);
-#endif
- return HEAP[dest];
+ 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) {
@@ -377,10 +334,17 @@ 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;
+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);
@@ -400,35 +364,71 @@ function assert(condition, text) {
// code then, whereas this function picks the right code at
// run-time.
-function setValue(ptr, value, type) {
+function setValue(ptr, value, type, noSafe) {
+ type = type || 'i8';
if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
- 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
+ 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) {
+function getValue(ptr, type, noSafe) {
+ type = type || 'i8';
if (type[type.length-1] === '*') type = 'i32'; // pointers are 32-bit
- 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
+ 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;
@@ -521,7 +521,7 @@ function alignMemoryPage(x) {
var HEAP;
#if USE_TYPED_ARRAYS == 1
-var IHEAP;
+var IHEAP, IHEAPU;
#if USE_FHEAP
var FHEAP;
#endif
@@ -532,6 +532,42 @@ var HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32;
var STACK_ROOT, STACKTOP, STACK_MAX;
var STATICTOP;
+#if USE_TYPED_ARRAYS
+var LAST_STATICTOP;
+function enlargeMemory() {
+ // LAST_STATICTOP is the previous top, TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top.
+#if ASSERTIONS
+ assert(STATICTOP >= TOTAL_MEMORY && LAST_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(TOTAL_MEMORY*1.25);
+ }
+#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_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}};
var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
@@ -544,6 +580,7 @@ var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
#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
diff --git a/src/runtime.js b/src/runtime.js
index a6261c74..0b36f967 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -56,7 +56,11 @@ var RuntimeGenerator = {
// An allocation that cannot be free'd
staticAlloc: function(size) {
- return RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP);
+ var ret = '';
+ if (USE_TYPED_ARRAYS) ret += 'LAST_STATICTOP = STATICTOP;'
+ ret += RuntimeGenerator.alloc(size, 'STATIC', INIT_HEAP);
+ if (USE_TYPED_ARRAYS) ret += '; if (STATICTOP >= TOTAL_MEMORY) enlargeMemory();'
+ return ret;