aboutsummaryrefslogtreecommitdiff
path: root/src/runtime.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime.js')
-rw-r--r--src/runtime.js184
1 files changed, 126 insertions, 58 deletions
diff --git a/src/runtime.js b/src/runtime.js
index 9bedfe68..a9265e70 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -25,26 +25,23 @@ var RuntimeGenerator = {
sep = sep || ';';
var ret = RuntimeGenerator.alloc(size, 'STACK', false, sep, USE_TYPED_ARRAYS != 2 || (isNumber(size) && parseInt(size) % {{{ STACK_ALIGN }}} == 0));
if (ASSERTIONS) {
- ret += sep + 'assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')';
+ ret += sep + '(assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')|0)';
}
return ret;
},
stackEnter: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
- var ret = 'var __stackBase__ = ' + (ASM_JS ? '0; __stackBase__ = ' : '') + 'STACKTOP';
- if (initial > 0) ret += '; STACKTOP = (STACKTOP + ' + initial + ')|0';
+ var ret = 'var sp=' + (ASM_JS ? '0;sp=' : '') + 'STACKTOP';
+ if (initial > 0) ret += ';STACKTOP=(STACKTOP+' + initial + ')|0';
if (USE_TYPED_ARRAYS == 2) {
assert(initial % Runtime.STACK_ALIGN == 0);
if (ASSERTIONS && Runtime.STACK_ALIGN == 4) {
- ret += '; assert(' + asmCoercion('!(STACKTOP&3)', 'i32') + ')';
+ ret += '; (assert(' + asmCoercion('!(STACKTOP&3)', 'i32') + ')|0)';
}
}
if (ASSERTIONS) {
- ret += '; assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')';
- }
- if (false) {
- ret += '; _memset(' + asmCoercion('__stackBase__', 'i32') + ', 0, ' + initial + ')';
+ ret += '; (assert(' + asmCoercion('(STACKTOP|0) < (STACK_MAX|0)', 'i32') + ')|0)';
}
return ret;
},
@@ -52,10 +49,10 @@ var RuntimeGenerator = {
stackExit: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
var ret = '';
- if (SAFE_HEAP) {
- ret += 'var i = __stackBase__; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }';
+ if (SAFE_HEAP && !ASM_JS) {
+ ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }';
}
- return ret += 'STACKTOP = __stackBase__';
+ return ret += 'STACKTOP=sp';
},
// An allocation that cannot normally be free'd (except through sbrk, which once
@@ -85,8 +82,8 @@ var RuntimeGenerator = {
// 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
makeBigInt: function(low, high, unsigned) {
- var unsignedRet = '(' + asmCoercion(makeSignOp(low, 'i32', 'un', 1, 1), 'float') + '+(' + asmCoercion(makeSignOp(high, 'i32', 'un', 1, 1), 'float') + '*' + asmEnsureFloat(4294967296, 'float') + '))';
- var signedRet = '(' + asmCoercion(makeSignOp(low, 'i32', 'un', 1, 1), 'float') + '+(' + asmCoercion(makeSignOp(high, 'i32', 're', 1, 1), 'float') + '*' + asmEnsureFloat(4294967296, 'float') + '))';
+ var unsignedRet = '(' + asmCoercion(makeSignOp(low, 'i32', 'un', 1, 1), 'double') + '+(' + asmCoercion(makeSignOp(high, 'i32', 'un', 1, 1), 'double') + '*' + asmEnsureFloat(4294967296, 'double') + '))';
+ var signedRet = '(' + asmCoercion(makeSignOp(low, 'i32', 'un', 1, 1), 'double') + '+(' + asmCoercion(makeSignOp(high, 'i32', 're', 1, 1), 'double') + '*' + asmEnsureFloat(4294967296, 'double') + '))';
if (typeof unsigned === 'string') return '(' + unsigned + ' ? ' + unsignedRet + ' : ' + signedRet + ')';
return unsigned ? unsignedRet : signedRet;
}
@@ -112,8 +109,7 @@ var Runtime = {
if (isNumber(target) && isNumber(quantum)) {
return Math.ceil(target/quantum)*quantum;
} else if (isNumber(quantum) && isPowerOfTwo(quantum)) {
- var logg = log2(quantum);
- return '((((' +target + ')+' + (quantum-1) + ')>>' + logg + ')<<' + logg + ')';
+ return '(((' +target + ')+' + (quantum-1) + ')&' + -quantum + ')';
}
return 'Math.ceil((' + target + ')/' + quantum + ')*' + quantum;
},
@@ -145,29 +141,32 @@ var Runtime = {
return l + h;
},
- //! Returns the size of a type, as C/C++ would have it (in 32-bit, for now), in bytes.
+ //! Returns the size of a type, as C/C++ would have it (in 32-bit), in bytes.
//! @param type The type, by name.
- getNativeTypeSize: function(type, quantumSize) {
- if (Runtime.QUANTUM_SIZE == 1) return 1;
- var size = {
- '%i1': 1,
- '%i8': 1,
- '%i16': 2,
- '%i32': 4,
- '%i64': 8,
- "%float": 4,
- "%double": 8
- }['%'+type]; // add '%' since float and double confuse Closure compiler as keys, and also spidermonkey as a compiler will remove 's from '_i8' etc
- if (!size) {
- if (type.charAt(type.length-1) == '*') {
- size = Runtime.QUANTUM_SIZE; // A pointer
- } else if (type[0] == 'i') {
- var bits = parseInt(type.substr(1));
- assert(bits % 8 == 0);
- size = bits/8;
+ getNativeTypeSize: function(type) {
+#if QUANTUM_SIZE == 1
+ return 1;
+#else
+ switch (type) {
+ case 'i1': case 'i8': return 1;
+ case 'i16': return 2;
+ case 'i32': return 4;
+ case 'i64': return 8;
+ case 'float': return 4;
+ case 'double': return 8;
+ default: {
+ if (type[type.length-1] === '*') {
+ return Runtime.QUANTUM_SIZE; // A pointer
+ } else if (type[0] === 'i') {
+ var bits = parseInt(type.substr(1));
+ assert(bits % 8 === 0);
+ return bits/8;
+ } else {
+ return 0;
+ }
}
}
- return size;
+#endif
},
//! Returns the size of a structure field, as C/C++ would have it (in 32-bit,
@@ -186,8 +185,11 @@ var Runtime = {
// type can be a native type or a struct (or null, for structs we only look at size here)
getAlignSize: function(type, size, vararg) {
// we align i64s and doubles on 64-bit boundaries, unlike x86
+#if TARGET_LE32 == 1
+ if (vararg) return 8;
+#endif
#if TARGET_LE32
- if (type == 'i64' || type == 'double' || vararg) return 8;
+ if (!vararg && (type == 'i64' || type == 'double')) return 8;
if (!type) return Math.min(size, 8); // align structures internally to 64 bits
#endif
return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);
@@ -201,20 +203,42 @@ var Runtime = {
type.alignSize = 0;
var diffs = [];
var prev = -1;
+ var index = 0;
type.flatIndexes = type.fields.map(function(field) {
+ index++;
var size, alignSize;
if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
alignSize = Runtime.getAlignSize(field, size);
} else if (Runtime.isStructType(field)) {
- size = Types.types[field].flatSize;
- alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+ if (field[1] === '0') {
+ // this is [0 x something]. When inside another structure like here, it must be at the end,
+ // and it adds no size
+ // XXX this happens in java-nbody for example... assert(index === type.fields.length, 'zero-length in the middle!');
+ size = 0;
+ if (Types.types[field]) {
+ alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+ } else {
+ alignSize = type.alignSize || QUANTUM_SIZE;
+ }
+ } else {
+ size = Types.types[field].flatSize;
+ alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+ }
} else if (field[0] == 'b') {
// bN, large number field, like a [N x i8]
size = field.substr(1)|0;
alignSize = 1;
+ } else if (field[0] === '<') {
+ // vector type
+ size = alignSize = Types.types[field].flatSize; // fully aligned
+ } else if (field[0] === 'i') {
+ // illegal integer field, that could not be legalized because it is an internal structure field
+ // it is ok to have such fields, if we just use them as markers of field size and nothing more complex
+ size = alignSize = parseInt(field.substr(1))/8;
+ assert(size % 1 === 0, 'cannot handle non-byte-size field ' + field);
} else {
- throw 'Unclear type in struct: ' + field + ', in ' + type.name_ + ' :: ' + dump(Types.types[type.name_]);
+ assert(false, 'invalid type for calculateStructAlignment');
}
if (type.packed) alignSize = 1;
type.alignSize = Math.max(type.alignSize, alignSize);
@@ -226,6 +250,11 @@ var Runtime = {
prev = curr;
return curr;
});
+ if (type.name_ && type.name_[0] === '[') {
+ // arrays have 2 elements, so we get the proper difference. then we scale here. that way we avoid
+ // allocating a potentially huge array for [999999 x i8] etc.
+ type.flatSize = parseInt(type.name_.substr(1))*type.flatSize/2;
+ }
type.flatSize = Runtime.alignMemory(type.flatSize, type.alignSize);
if (diffs.length == 0) {
type.flatFactor = type.flatSize;
@@ -332,28 +361,51 @@ var Runtime = {
for (var i = 0; i < Runtime.functionPointers.length; i++) {
if (!Runtime.functionPointers[i]) {
Runtime.functionPointers[i] = func;
- return 2 + 2*i;
+ return {{{ FUNCTION_POINTER_ALIGNMENT }}}*(1 + i);
}
}
throw 'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.';
#else
var table = FUNCTION_TABLE;
var ret = table.length;
+ assert(ret % {{{ FUNCTION_POINTER_ALIGNMENT }}} === 0);
table.push(func);
- table.push(0);
+ for (var i = 0; i < {{{ FUNCTION_POINTER_ALIGNMENT }}}-1; i++) table.push(0);
return ret;
#endif
},
removeFunction: function(index) {
#if ASM_JS
- Runtime.functionPointers[(index-2)/2] = null;
+ Runtime.functionPointers[(index-{{{ FUNCTION_POINTER_ALIGNMENT }}})/{{{ FUNCTION_POINTER_ALIGNMENT }}}] = null;
#else
var table = FUNCTION_TABLE;
table[index] = null;
#endif
},
+ getAsmConst: function(code, numArgs) {
+ // code is a constant string on the heap, so we can cache these
+ if (!Runtime.asmConstCache) Runtime.asmConstCache = {};
+ var func = Runtime.asmConstCache[code];
+ if (func) return func;
+ var args = [];
+ for (var i = 0; i < numArgs; i++) {
+ args.push(String.fromCharCode(36) + i); // $0, $1 etc
+ }
+ code = Pointer_stringify(code);
+ if (code[0] === '"') {
+ // tolerate EM_ASM("..code..") even though EM_ASM(..code..) is correct
+ if (code.indexOf('"', 1) === code.length-1) {
+ code = code.substr(1, code.length-2);
+ } else {
+ // something invalid happened, e.g. EM_ASM("..code($0)..", input)
+ abort('invalid EM_ASM input |' + code + '|. Please use EM_ASM(..code..) (no quotes) or EM_ASM({ ..code($0).. }, input) (to input values)');
+ }
+ }
+ return Runtime.asmConstCache[code] = eval('(function(' + args.join(',') + '){ ' + code + ' })'); // new Function does not allow upvars in node
+ },
+
warnOnce: function(text) {
if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};
if (!Runtime.warnOnce.shown[text]) {
@@ -367,7 +419,7 @@ var Runtime = {
getFuncWrapper: function(func, sig) {
assert(sig);
if (!Runtime.funcWrappers[func]) {
- Runtime.funcWrappers[func] = function() {
+ Runtime.funcWrappers[func] = function dynCall_wrapper() {
return Runtime.dynCall(sig, func, arguments);
};
}
@@ -376,40 +428,56 @@ var Runtime = {
// Returns a processor of UTF.
// processCChar() receives characters from a C-like UTF representation and returns JS string fragments.
+ // See RFC3629 for details, the bytes are assumed to be valid UTF-8
// processJSString() receives a JS string and returns a C-like UTF representation in an array
UTF8Processor: function() {
var buffer = [];
var needed = 0;
this.processCChar = function (code) {
- code = code & 0xff;
- if (needed) {
- buffer.push(code);
- needed--;
- }
+ code = code & 0xFF;
+
if (buffer.length == 0) {
- if (code < 128) return String.fromCharCode(code);
+ if ((code & 0x80) == 0x00) { // 0xxxxxxx
+ return String.fromCharCode(code);
+ }
buffer.push(code);
- if (code > 191 && code < 224) {
+ if ((code & 0xE0) == 0xC0) { // 110xxxxx
needed = 1;
- } else {
+ } else if ((code & 0xF0) == 0xE0) { // 1110xxxx
needed = 2;
+ } else { // 11110xxx
+ needed = 3;
}
return '';
}
- if (needed > 0) return '';
+
+ if (needed) {
+ buffer.push(code);
+ needed--;
+ if (needed > 0) return '';
+ }
+
var c1 = buffer[0];
var c2 = buffer[1];
var c3 = buffer[2];
+ var c4 = buffer[3];
var ret;
- if (c1 > 191 && c1 < 224) {
- ret = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
+ if (buffer.length == 2) {
+ ret = String.fromCharCode(((c1 & 0x1F) << 6) | (c2 & 0x3F));
+ } else if (buffer.length == 3) {
+ ret = String.fromCharCode(((c1 & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));
} else {
- ret = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
+ // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
+ var codePoint = ((c1 & 0x07) << 18) | ((c2 & 0x3F) << 12) |
+ ((c3 & 0x3F) << 6) | (c4 & 0x3F);
+ ret = String.fromCharCode(
+ Math.floor((codePoint - 0x10000) / 0x400) + 0xD800,
+ (codePoint - 0x10000) % 0x400 + 0xDC00);
}
buffer.length = 0;
return ret;
}
- this.processJSString = function(string) {
+ this.processJSString = function processJSString(string) {
string = unescape(encodeURIComponent(string));
var ret = [];
for (var i = 0; i < string.length; i++) {
@@ -497,7 +565,7 @@ function getRuntime() {
// Converts a value we have as signed, into an unsigned value. For
// example, -1 in int32 would be a very large number as unsigned.
-function unSign(value, bits, ignore, sig) {
+function unSign(value, bits, ignore) {
if (value >= 0) {
return value;
}
@@ -510,7 +578,7 @@ function unSign(value, bits, ignore, sig) {
// Converts a value we have as unsigned, into a signed value. For
// example, 200 in a uint8 would be a negative number.
-function reSign(value, bits, ignore, sig) {
+function reSign(value, bits, ignore) {
if (value <= 0) {
return value;
}