summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js14
-rw-r--r--src/compiler.js7
-rw-r--r--src/intertyper.js2
-rw-r--r--src/jsifier.js37
-rw-r--r--src/library.js107
-rw-r--r--src/library_gc.js2
-rw-r--r--src/library_gl.js289
-rw-r--r--src/library_sdl.js35
-rw-r--r--src/modules.js22
-rw-r--r--src/parseTools.js45
-rw-r--r--src/preamble.js57
-rw-r--r--src/relooper/Relooper.cpp84
-rw-r--r--src/relooper/test.txt4
-rw-r--r--src/relooper/test2.txt15
-rw-r--r--src/relooper/test3.txt38
-rw-r--r--src/relooper/test4.txt21
-rw-r--r--src/relooper/test6.txt15
-rw-r--r--src/relooper/test_debug.txt15
-rw-r--r--src/relooper/test_fuzz1.txt13
-rw-r--r--src/relooper/test_fuzz5.txt27
-rw-r--r--src/relooper/test_inf.txt651
-rw-r--r--src/runtime.js4
-rw-r--r--src/settings.js17
-rw-r--r--src/shell.html2
24 files changed, 936 insertions, 587 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index c930231f..ecb5ea6b 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -18,6 +18,7 @@ function recomputeLines(func) {
// Handy sets
var BRANCH_INVOKE = set('branch', 'invoke');
+var LABEL_ENDERS = set('branch', 'return');
var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic');
var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam');
@@ -88,7 +89,7 @@ function analyzer(data, sidePass) {
// Internal line
if (!currLabelFinished) {
item.functions.slice(-1)[0].labels.slice(-1)[0].lines.push(subItem); // If this line fails, perhaps missing a label?
- if (subItem.intertype === 'branch') {
+ if (subItem.intertype in LABEL_ENDERS) {
currLabelFinished = true;
}
} else {
@@ -121,7 +122,8 @@ function analyzer(data, sidePass) {
// Legalization
if (USE_TYPED_ARRAYS == 2) {
function getLegalVars(base, bits, allowLegal) {
- if (allowLegal && bits <= 32) return [{ ident: base, bits: bits }];
+ bits = bits || 32; // things like pointers are all i32, but show up as 0 bits from getBits
+ if (allowLegal && bits <= 32) return [{ ident: base + ('i' + bits in Runtime.INT_TYPES ? '' : '$0'), bits: bits }];
if (isNumber(base)) return getLegalLiterals(base, bits);
var ret = new Array(Math.ceil(bits/32));
var i = 0;
@@ -646,13 +648,7 @@ function analyzer(data, sidePass) {
default: throw 'Invalid mathop for legalization: ' + [value.op, item.lineNum, dump(item)];
}
// Do the legalization
- var sourceElements;
- if (sourceBits <= 32) {
- // The input is a legal type
- sourceElements = [{ ident: value.params[0].ident, bits: sourceBits }];
- } else {
- sourceElements = getLegalVars(value.params[0].ident, sourceBits);
- }
+ var sourceElements = getLegalVars(value.params[0].ident, sourceBits, true);
if (!isNumber(shifts)) {
// We can't statically legalize this, do the operation at runtime TODO: optimize
assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits');
diff --git a/src/compiler.js b/src/compiler.js
index 0b43842e..3047daf1 100644
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -172,20 +172,21 @@ assert(!(USE_TYPED_ARRAYS === 2 && QUANTUM_SIZE !== 4), 'For USE_TYPED_ARRAYS ==
if (ASM_JS) {
assert(!ALLOW_MEMORY_GROWTH, 'Cannot grow asm.js heap');
assert((TOTAL_MEMORY&(TOTAL_MEMORY-1)) == 0, 'asm.js heap must be power of 2');
+ assert(DISABLE_EXCEPTION_CATCHING == 1, 'asm.js does not support C++ exceptions yet');
}
assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB)); // shared libraries must have named globals
// Output some info and warnings based on settings
if (phase == 'pre') {
- if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_STACK || INIT_HEAP ||
+ if (!MICRO_OPTS || !RELOOP || ASSERTIONS || CHECK_SIGNS || CHECK_OVERFLOWS || INIT_HEAP ||
!SKIP_STACK_IN_SMALL || SAFE_HEAP || !DISABLE_EXCEPTION_CATCHING) {
print('// Note: Some Emscripten settings will significantly limit the speed of the generated code.');
} else {
print('// Note: For maximum-speed code, see "Optimizing Code" on the Emscripten wiki, https://github.com/kripken/emscripten/wiki/Optimizing-Code');
}
- if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS) {
+ if (DOUBLE_MODE || CORRECT_SIGNS || CORRECT_OVERFLOWS || CORRECT_ROUNDINGS || CHECK_HEAP_ALIGN) {
print('// Note: Some Emscripten settings may limit the speed of the generated code.');
}
}
@@ -198,7 +199,7 @@ load('parseTools.js');
load('intertyper.js');
load('analyzer.js');
load('jsifier.js');
-if (RELOOP) load('relooper.js')
+if (RELOOP) load(RELOOPER)
globalEval(processMacros(preprocess(read('runtime.js'))));
Runtime.QUANTUM_SIZE = QUANTUM_SIZE;
diff --git a/src/intertyper.js b/src/intertyper.js
index c1a98354..6c88e765 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -741,10 +741,12 @@ function intertyper(data, sidePass, baseLineNums) {
processItem: function(item) {
item.intertype = 'atomic';
if (item.tokens[0].text == 'atomicrmw') {
+ if (item.tokens[1].text == 'volatile') item.tokens.splice(1, 1);
item.op = item.tokens[1].text;
item.tokens.splice(1, 1);
} else {
assert(item.tokens[0].text == 'cmpxchg')
+ if (item.tokens[1].text == 'volatile') item.tokens.splice(1, 1);
item.op = 'cmpxchg';
}
var last = getTokenIndexByText(item.tokens, ';');
diff --git a/src/jsifier.js b/src/jsifier.js
index 4af522b4..ff58ece2 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -375,6 +375,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
+ Variables.globals[item.ident].targetIdent = item.value.ident;
var value = Variables.globals[item.ident].resolvedAlias = finalizeLLVMParameter(item.value);
var fix = '';
if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
@@ -505,7 +506,7 @@ function JSify(data, functionsOnly, givenFunctions) {
item.JS = '';
} else if (LibraryManager.library.hasOwnProperty(shortident)) {
item.JS = addFromLibrary(shortident);
- } else {
+ } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) {
item.JS = 'var ' + item.ident + '; // stub for ' + item.ident;
if (WARN_ON_UNDEFINED_SYMBOLS || ASM_JS) { // always warn on undefs in asm, since it breaks validation
warn('Unresolved symbol: ' + item.ident);
@@ -913,7 +914,11 @@ function JSify(data, functionsOnly, givenFunctions) {
case VAR_NATIVIZED:
if (isNumber(item.ident)) {
// Direct write to a memory address; this may be an intentional segfault, if not, it is a bug in the source
- return 'throw "fault on write to ' + item.ident + '";';
+ if (ASM_JS) {
+ return 'abort(' + item.ident + ')';
+ } else {
+ return 'throw "fault on write to ' + item.ident + '";';
+ }
}
return item.ident + '=' + value + ';'; // We have the actual value here
break;
@@ -1199,10 +1204,13 @@ function JSify(data, functionsOnly, givenFunctions) {
switch (item.op) {
case 'add': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue+' + param2, type, null, null, null, null, ',') + ',tempValue)';
case 'sub': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue-' + param2, type, null, null, null, null, ',') + ',tempValue)';
+ case 'or': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue|' + param2, type, null, null, null, null, ',') + ',tempValue)';
+ case 'and': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue&' + param2, type, null, null, null, null, ',') + ',tempValue)';
+ case 'xor': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue^' + param2, type, null, null, null, null, ',') + ',tempValue)';
case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type, null, null, null, null, ',') + ',tempValue)';
case 'cmpxchg': {
var param3 = finalizeLLVMParameter(item.params[2]);
- return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)';
+ return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==(' + param2 + '|0) ? ' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ' : 0),tempValue)';
}
default: throw 'unhandled atomic op: ' + item.op;
}
@@ -1221,6 +1229,15 @@ function JSify(data, functionsOnly, givenFunctions) {
var impl = item.ident ? getVarImpl(item.funcData, item.ident) : VAR_EMULATED;
switch (impl) {
case VAR_NATIVIZED: {
+ if (isNumber(item.ident)) {
+ item.assignTo = null;
+ // Direct read from a memory address; this may be an intentional segfault, if not, it is a bug in the source
+ if (ASM_JS) {
+ return 'abort(' + item.ident + ')';
+ } else {
+ return 'throw "fault on read from ' + item.ident + '";';
+ }
+ }
return value; // We have the actual value here
}
case VAR_EMULATED: return makeGetValue(value, 0, item.type, 0, item.unsigned, 0, item.align);
@@ -1244,7 +1261,7 @@ function JSify(data, functionsOnly, givenFunctions) {
makeFuncLineActor('insertvalue', function(item) {
assert(item.indexes.length == 1); // TODO: see extractvalue
var ret = '(', ident;
- if (item.ident === 'undef') {
+ if (item.ident === '0') {
item.ident = 'tempValue';
ret += item.ident + ' = [' + makeEmptyStruct(item.type) + '], ';
}
@@ -1284,6 +1301,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
+ ident = Variables.resolveAliasToIdent(ident);
var shortident = ident.slice(1);
var callIdent = LibraryManager.getRootIdent(shortident);
if (callIdent) {
@@ -1401,6 +1419,9 @@ function JSify(data, functionsOnly, givenFunctions) {
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
+ } else if (SAFE_DYNCALLS) {
+ assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
+ callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
}
callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
@@ -1567,9 +1588,11 @@ function JSify(data, functionsOnly, givenFunctions) {
var shellParts = read(shellFile).split('{{BODY}}');
print(shellParts[1]);
// Print out some useful metadata (for additional optimizations later, like the eliminator)
- print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
- return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
- })) + '\n');
+ if (EMIT_GENERATED_FUNCTIONS) {
+ print('// EMSCRIPTEN_GENERATED_FUNCTIONS: ' + JSON.stringify(keys(Functions.implementedFunctions).filter(function(func) {
+ return IGNORED_FUNCTIONS.indexOf(func.ident) < 0;
+ })) + '\n');
+ }
PassManager.serialize();
diff --git a/src/library.js b/src/library.js
index d0f73fdd..1cd7e3f5 100644
--- a/src/library.js
+++ b/src/library.js
@@ -3363,14 +3363,15 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.ECHILD);
return -1;
},
- perror__deps: ['puts', 'putc', 'strerror', '__errno_location'],
+ perror__deps: ['puts', 'fputs', 'fputc', 'strerror', '__errno_location'],
perror: function(s) {
// void perror(const char *s);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/perror.html
+ var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}};
if (s) {
- _puts(s);
- _putc(':'.charCodeAt(0));
- _putc(' '.charCodeAt(0));
+ _fputs(s, stdout);
+ _fputc(':'.charCodeAt(0), stdout);
+ _fputc(' '.charCodeAt(0), stdout);
}
var errnum = {{{ makeGetValue('___errno_location()', '0', 'i32') }}};
_puts(_strerror(errnum));
@@ -4313,8 +4314,9 @@ LibraryManager.library = {
ptr = ptr|0; value = value|0; num = num|0;
var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
stop = (ptr + num)|0;
- if (num|0 >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}}) {
+ if ((num|0) >= {{{ SEEK_OPTIMAL_ALIGN_MIN }}}) {
// This is unaligned, but quite large, so work hard to get to aligned settings
+ value = value & 0xff;
unaligned = ptr & 3;
value4 = value | (value << 8) | (value << 16) | (value << 24);
stop4 = stop & ~3;
@@ -6701,6 +6703,9 @@ LibraryManager.library = {
pthread_mutexattr_destroy: function() {},
pthread_mutex_lock: function() {},
pthread_mutex_unlock: function() {},
+ pthread_mutex_trylock: function() {
+ return 0;
+ },
pthread_cond_init: function() {},
pthread_cond_destroy: function() {},
pthread_cond_broadcast: function() {},
@@ -6743,17 +6748,27 @@ LibraryManager.library = {
pthread_key_create: function(key, destructor) {
if (!_pthread_key_create.keys) _pthread_key_create.keys = {};
- _pthread_key_create.keys[key] = null;
+ // values start at 0
+ _pthread_key_create.keys[key] = 0;
},
pthread_getspecific: function(key) {
- return _pthread_key_create.keys[key];
+ return _pthread_key_create.keys[key] || 0;
},
pthread_setspecific: function(key, value) {
_pthread_key_create.keys[key] = value;
},
+ pthread_key_delete: ['$ERRNO_CODES'],
+ pthread_key_delete: function(key) {
+ if (_pthread_key_create.keys[key]) {
+ delete _pthread_key_create.keys[key];
+ return 0;
+ }
+ return ERRNO_CODES.EINVAL;
+ },
+
pthread_cleanup_push: function(routine, arg) {
__ATEXIT__.push({ func: function() { Runtime.dynCall('vi', routine, [arg]) } })
_pthread_cleanup_push.level = __ATEXIT__.length;
@@ -7258,23 +7273,56 @@ LibraryManager.library = {
},
select: function(nfds, readfds, writefds, exceptfds, timeout) {
- // only readfds are supported, not writefds or exceptfds
+ // readfds are supported,
+ // writefds checks socket open status
+ // exceptfds not supported
// timeout is always 0 - fully async
- assert(!writefds && !exceptfds);
- var ret = 0;
- var l = {{{ makeGetValue('readfds', 0, 'i32') }}};
- var h = {{{ makeGetValue('readfds', 4, 'i32') }}};
- nfds = Math.min(64, nfds); // fd sets have 64 bits
- for (var fd = 0; fd < nfds; fd++) {
- var bit = fd % 32, int = fd < 32 ? l : h;
- if (int & (1 << bit)) {
- // index is in the set, check if it is ready for read
- var info = Sockets.fds[fd];
- if (!info) continue;
- if (info.hasData()) ret++;
+ assert(!exceptfds);
+
+ function canRead(info) {
+ // make sure hasData exists.
+ // we do create it when the socket is connected,
+ // but other implementations may create it lazily
+ return info.hasData && info.hasData();
+ }
+
+ function canWrite(info) {
+ // make sure socket exists.
+ // we do create it when the socket is connected,
+ // but other implementations may create it lazily
+ return info.socket && (info.socket.readyState == info.socket.OPEN);
+ }
+
+ function checkfds(nfds, fds, can) {
+ if (!fds) return 0;
+
+ var bitsSet = 0;
+ var dstLow = 0;
+ var dstHigh = 0;
+ var srcLow = {{{ makeGetValue('fds', 0, 'i32') }}};
+ var srcHigh = {{{ makeGetValue('fds', 4, 'i32') }}};
+ nfds = Math.min(64, nfds); // fd sets have 64 bits
+
+ for (var fd = 0; fd < nfds; fd++) {
+ var mask = 1 << (fd % 32), int = fd < 32 ? srcLow : srcHigh;
+ if (int & mask) {
+ // index is in the set, check if it is ready for read
+ var info = Sockets.fds[fd];
+ if (info && can(info)) {
+ // set bit
+ fd < 32 ? (dstLow = dstLow | mask) : (dstHigh = dstHigh | mask);
+ bitsSet++;
+ }
+ }
}
+
+ {{{ makeSetValue('fds', 0, 'dstLow', 'i32') }}};
+ {{{ makeSetValue('fds', 4, 'dstHigh', 'i32') }}};
+ return bitsSet;
}
- return ret;
+
+ return checkfds(nfds, readfds, canRead)
+ + checkfds(nfds, writefds, canWrite);
},
// pty.h
@@ -7320,6 +7368,23 @@ LibraryManager.library = {
emscripten_random: function() {
return Math.random();
},
+
+ emscripten_jcache_printf___deps: ['_formatString'],
+ emscripten_jcache_printf_: function(varargs) {
+ var MAX = 10240;
+ if (!_emscripten_jcache_printf_.buffer) {
+ _emscripten_jcache_printf_.buffer = _malloc(MAX);
+ }
+ var i = 0;
+ do {
+ var curr = {{{ makeGetValue('varargs', 'i*4', 'i8') }}};
+ {{{ makeSetValue('_emscripten_jcache_printf_.buffer', 'i', 'curr', 'i8') }}};
+ i++;
+ assert(i*4 < MAX);
+ } while (curr != 0);
+ Module.print(intArrayToString(__formatString(_emscripten_jcache_printf_.buffer, varargs + i*4)).replace('\\n', ''));
+ Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free
+ },
};
function autoAddDeps(object, name) {
diff --git a/src/library_gc.js b/src/library_gc.js
index 083019ca..f6db74d8 100644
--- a/src/library_gc.js
+++ b/src/library_gc.js
@@ -4,7 +4,7 @@ if (GC_SUPPORT) {
EXPORTED_FUNCTIONS['_realloc'] = 1;
var LibraryGC = {
- $GC__deps: ['sbrk', 'realloc'],
+ $GC__deps: ['sbrk', 'realloc', 'calloc'],
$GC: {
ALLOCATIONS_TO_GC: 1*1024*1024,
diff --git a/src/library_gl.js b/src/library_gl.js
index 027b2841..4977d2e9 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -19,6 +19,28 @@ var LibraryGL = {
uniforms: [],
shaders: [],
+#if FULL_ES2
+ clientBuffers: [],
+ enabledClientBuffers: [],
+#endif
+ currArrayBuffer: 0,
+ currElementArrayBuffer: 0,
+
+ byteSizeByTypeRoot: 0x1400, // GL_BYTE
+ byteSizeByType: [
+ 1, // GL_BYTE
+ 1, // GL_UNSIGNED_BYTE
+ 2, // GL_SHORT
+ 2, // GL_UNSIGNED_SHORT
+ 4, // GL_INT
+ 4, // GL_UNSIGNED_INT
+ 4, // GL_FLOAT
+ 2, // GL_2_BYTES
+ 3, // GL_3_BYTES
+ 4, // GL_4_BYTES
+ 8 // GL_DOUBLE
+ ],
+
uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation
packAlignment: 4, // default alignment is 4 bytes
@@ -176,12 +198,48 @@ var LibraryGL = {
}
},
+#if FULL_ES2
+ calcBufLength: function(size, type, stride, count) {
+ if (stride > 0) {
+ return count * stride; // XXXvlad this is not exactly correct I don't think
+ }
+ var typeSize = GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
+ return size * typeSize * count;
+ },
+
+ preDrawHandleClientVertexAttribBindings: function(count) {
+ GL.resetBufferBinding = false;
+ for (var i = 0; i < GL.maxVertexAttribs; ++i) {
+ if (!GL.enabledClientBuffers[i] || !GL.clientBuffers[i]) continue;
+
+ GL.resetBufferBinding = true;
+
+ var cb = GL.clientBuffers[i];
+
+ var buf = Module.ctx.createBuffer();
+ Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, buf);
+ Module.ctx.bufferData(Module.ctx.ARRAY_BUFFER,
+ HEAPU8.subarray(cb.ptr, cb.ptr + GL.calcBufLength(cb.size, cb.type, cb.stride, count)),
+ Module.ctx.DYNAMIC_DRAW);
+ Module.ctx.vertexAttribPointer(i, cb.size, cb.type, cb.normalized, cb.stride, 0);
+ }
+ },
+
+ postDrawHandleClientVertexAttribBindings: function() {
+ if (GL.resetBufferBinding) {
+ Module.ctx.bindBuffer(Module.ctx.ARRAY_BUFFER, GL.buffers[GL.currArrayBuffer]);
+ }
+ },
+#endif
+
initExtensions: function() {
if (GL.initExtensions.done) return;
GL.initExtensions.done = true;
if (!Module.useWebGL) return; // an app might link both gl and 2d backends
+ GL.maxVertexAttribs = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_ATTRIBS);
+
GL.compressionExt = Module.ctx.getExtension('WEBGL_compressed_texture_s3tc') ||
Module.ctx.getExtension('MOZ_WEBGL_compressed_texture_s3tc') ||
Module.ctx.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc');
@@ -456,6 +514,9 @@ var LibraryGL = {
var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
Module.ctx.deleteBuffer(GL.buffers[id]);
GL.buffers[id] = null;
+
+ if (id == GL.currArrayBuffer) GL.currArrayBuffer = 0;
+ if (id == GL.currElementArrayBuffer) GL.currElementArrayBuffer = 0;
}
},
@@ -474,11 +535,9 @@ var LibraryGL = {
},
glIsBuffer: function(buffer) {
- var fb = GL.buffers[buffer];
- if (typeof(fb) == 'undefined') {
- return 0;
- }
- return Module.ctx.isBuffer(fb);
+ var b = GL.buffers[buffer];
+ if (!b) return 0;
+ return Module.ctx.isBuffer(b);
},
glGenRenderbuffers__sig: 'vii',
@@ -509,11 +568,9 @@ var LibraryGL = {
},
glIsRenderbuffer: function(renderbuffer) {
- var fb = GL.renderbuffers[renderbuffer];
- if (typeof(fb) == 'undefined') {
- return 0;
- }
- return Module.ctx.isRenderbuffer(fb);
+ var rb = GL.renderbuffers[renderbuffer];
+ if (!rb) return 0;
+ return Module.ctx.isRenderbuffer(rb);
},
glGetUniformfv: function(program, location, params) {
@@ -554,6 +611,11 @@ var LibraryGL = {
},
glGetVertexAttribfv: function(index, pname, params) {
+#if FULL_ES2
+ if (GL.clientBuffers[index]) {
+ Module.printErr("glGetVertexAttribfv on client-side array: not supported, bad data returned");
+ }
+#endif
var data = Module.ctx.getVertexAttrib(index, pname);
if (typeof data == 'number') {
{{{ makeSetValue('params', '0', 'data', 'float') }}};
@@ -565,6 +627,11 @@ var LibraryGL = {
},
glGetVertexAttribiv: function(index, pname, params) {
+#if FULL_ES2
+ if (GL.clientBuffers[index]) {
+ Module.printErr("glGetVertexAttribiv on client-side array: not supported, bad data returned");
+ }
+#endif
var data = Module.ctx.getVertexAttrib(index, pname);
if (typeof data == 'number' || typeof data == 'boolean') {
{{{ makeSetValue('params', '0', 'data', 'i32') }}};
@@ -576,6 +643,11 @@ var LibraryGL = {
},
glGetVertexAttribPointerv: function(index, pname, pointer) {
+#if FULL_ES2
+ if (GL.clientBuffers[index]) {
+ Module.printErr("glGetVertexAttribPointer on client-side array: not supported, bad data returned");
+ }
+#endif
{{{ makeSetValue('pointer', '0', 'Module.ctx.getVertexAttribOffset(index, pname)', 'i32') }}};
},
@@ -731,6 +803,12 @@ var LibraryGL = {
glBindBuffer__sig: 'vii',
glBindBuffer: function(target, buffer) {
+ if (target == Module.ctx.ARRAY_BUFFER) {
+ GL.currArrayBuffer = buffer;
+ } else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
+ GL.currElementArrayBuffer = buffer;
+ }
+
Module.ctx.bindBuffer(target, buffer ? GL.buffers[buffer] : null);
},
@@ -858,11 +936,9 @@ var LibraryGL = {
},
glIsShader: function(shader) {
- var fb = GL.shaders[shader];
- if (typeof(fb) == 'undefined') {
- return 0;
- }
- return Module.ctx.isShader(fb);
+ var s = GL.shaders[shader];
+ if (!s) return 0;
+ return Module.ctx.isShader(s);
},
glCreateProgram__sig: 'i',
@@ -975,9 +1051,7 @@ var LibraryGL = {
glIsFramebuffer__sig: 'ii',
glIsFramebuffer: function(framebuffer) {
var fb = GL.framebuffers[framebuffer];
- if (typeof(fb) == 'undefined') {
- return 0;
- }
+ if (!fb) return 0;
return Module.ctx.isFramebuffer(fb);
},
@@ -1016,6 +1090,7 @@ var LibraryGL = {
0x809E: 1, // GL_SAMPLE_ALPHA_TO_COVERAGE
0x80A0: 1 // GL_SAMPLE_COVERAGE
};
+
_glEnable = function(cap) {
// Clean up the renderer on any change to the rendering state. The optimization of
// skipping renderer setup is aimed at the case of multiple glDraw* right after each other
@@ -1057,6 +1132,17 @@ var LibraryGL = {
return Module.ctx.isEnabled(cap);
};
+ var glGetBooleanv = _glGetBooleanv;
+ _glGetBooleanv = function(pname, p) {
+ var attrib = GLEmulation.getAttributeFromCapability(pname);
+ if (attrib !== null) {
+ var result = GL.immediate.enabledClientAttributes[attrib];
+ {{{ makeSetValue('p', '0', 'result === true ? 1 : 0', 'i8') }}};
+ return;
+ }
+ glGetBooleanv(pname, p);
+ };
+
var glGetIntegerv = _glGetIntegerv;
_glGetIntegerv = function(pname, params) {
switch (pname) {
@@ -1336,27 +1422,15 @@ var LibraryGL = {
_glBindBuffer = function(target, buffer) {
glBindBuffer(target, buffer);
if (target == Module.ctx.ARRAY_BUFFER) {
- GL.currArrayBuffer = buffer;
if (GLEmulation.currentVao) {
assert(GLEmulation.currentVao.arrayBuffer == buffer || GLEmulation.currentVao.arrayBuffer == 0 || buffer == 0, 'TODO: support for multiple array buffers in vao');
GLEmulation.currentVao.arrayBuffer = buffer;
}
} else if (target == Module.ctx.ELEMENT_ARRAY_BUFFER) {
- GL.currElementArrayBuffer = buffer;
if (GLEmulation.currentVao) GLEmulation.currentVao.elementArrayBuffer = buffer;
}
};
- var glDeleteBuffers = _glDeleteBuffers;
- _glDeleteBuffers = function(n, buffers) {
- glDeleteBuffers(n, buffers);
- for (var i = 0; i < n; i++) {
- var buffer = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
- if (buffer == GL.currArrayBuffer) GL.currArrayBuffer = 0;
- if (buffer == GL.currElementArrayBuffer) GL.currElementArrayBuffer = 0;
- }
- };
-
var glGetFloatv = _glGetFloatv;
_glGetFloatv = function(pname, params) {
if (pname == 0x0BA6) { // GL_MODELVIEW_MATRIX
@@ -1411,6 +1485,22 @@ var LibraryGL = {
};
},
+ getAttributeFromCapability: function(cap) {
+ var attrib = null;
+ switch (cap) {
+ case 0x8078: // GL_TEXTURE_COORD_ARRAY
+ case 0x0de1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it
+ attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
+ case 0x8074: // GL_VERTEX_ARRAY
+ attrib = GL.immediate.VERTEX; break;
+ case 0x8075: // GL_NORMAL_ARRAY
+ attrib = GL.immediate.NORMAL; break;
+ case 0x8076: // GL_COLOR_ARRAY
+ attrib = GL.immediate.COLOR; break;
+ }
+ return attrib;
+ },
+
getProcAddress: function(name) {
name = name.replace('EXT', '').replace('ARB', '');
// Do the translation carefully because of closure
@@ -1544,7 +1634,7 @@ var LibraryGL = {
// GL Immediate mode
$GLImmediate__postset: 'GL.immediate.setupFuncs(); Browser.moduleContextCreatedCallbacks.push(function() { GL.immediate.init() });',
- $GLImmediate__deps: ['$Browser', '$GL'],
+ $GLImmediate__deps: ['$Browser', '$GL', '$GLEmulation'],
$GLImmediate: {
MAX_TEXTURES: 7,
@@ -1593,17 +1683,6 @@ var LibraryGL = {
clientActiveTexture: 0,
clientColor: null,
- byteSizeByTypeRoot: 0x1400, // GL_BYTE
- byteSizeByType: [
- 1, // GL_BYTE
- 1, // GL_UNSIGNED_BYTE
- 2, // GL_SHORT
- 2, // GL_UNSIGNED_SHORT
- 4, // GL_INT
- 4, // GL_UNSIGNED_INT
- 4 // GL_FLOAT
- ],
-
setClientAttribute: function(name, size, type, stride, pointer) {
var attrib = this.clientAttributes[name];
attrib.name = name;
@@ -1679,7 +1758,7 @@ var LibraryGL = {
#endif
this.enabledClientAttributes[name] = true;
this.setClientAttribute(name, size, type, 0, this.rendererComponentPointer);
- this.rendererComponentPointer += size * this.byteSizeByType[type - this.byteSizeByTypeRoot];
+ this.rendererComponentPointer += size * GL.byteSizeByType[type - GL.byteSizeByTypeRoot];
} else {
this.rendererComponents[name]++;
}
@@ -1703,7 +1782,7 @@ var LibraryGL = {
cacheItem = temp ? temp : (cacheItem[attribute.name] = GL.immediate.rendererCacheItemTemplate.slice());
temp = cacheItem[attribute.size];
cacheItem = temp ? temp : (cacheItem[attribute.size] = GL.immediate.rendererCacheItemTemplate.slice());
- var typeIndex = attribute.type - GL.immediate.byteSizeByTypeRoot; // ensure it starts at 0 to keep the cache items dense
+ var typeIndex = attribute.type - GL.byteSizeByTypeRoot; // ensure it starts at 0 to keep the cache items dense
temp = cacheItem[typeIndex];
cacheItem = temp ? temp : (cacheItem[typeIndex] = GL.immediate.rendererCacheItemTemplate.slice());
}
@@ -2139,7 +2218,7 @@ var LibraryGL = {
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
if (!attribute) break;
- var size = attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot];
+ var size = attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
if (size % 4 != 0) size += 4 - (size % 4); // align everything
attribute.offset = bytes;
bytes += size;
@@ -2151,7 +2230,7 @@ var LibraryGL = {
for (var i = 0; i < attributes.length; i++) {
var attribute = attributes[i];
if (!attribute) break;
- var size4 = Math.floor((attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot])/4);
+ var size4 = Math.floor((attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot])/4);
for (var j = 0; j < count; j++) {
for (var k = 0; k < size4; k++) { // copy in chunks of 4 bytes, our alignment makes this possible
HEAP32[((start + attribute.offset + bytes*j)>>2) + k] = HEAP32[(attribute.pointer>>2) + j*size4 + k];
@@ -2169,7 +2248,7 @@ var LibraryGL = {
assert((attribute.offset - bytes)%4 == 0); // XXX assuming 4-alignment
bytes += attribute.offset - bytes;
}
- bytes += attribute.size * GL.immediate.byteSizeByType[attribute.type - GL.immediate.byteSizeByTypeRoot];
+ bytes += attribute.size * GL.byteSizeByType[attribute.type - GL.byteSizeByTypeRoot];
if (bytes % 4 != 0) bytes += 4 - (bytes % 4); // XXX assuming 4-alignment
}
assert(beginEnd || bytes <= stride); // if not begin-end, explicit stride should make sense with total byte size
@@ -2304,8 +2383,10 @@ var LibraryGL = {
glVertex2fv: function(p) {
_glVertex3f({{{ makeGetValue('p', '0', 'float') }}}, {{{ makeGetValue('p', '4', 'float') }}}, 0);
},
+
+ glVertex3i: 'glVertex3f',
- glVertex2i: function() { throw 'glVertex2i: TODO' },
+ glVertex2i: 'glVertex3f',
glTexCoord2i: function(u, v) {
#if ASSERTIONS
@@ -2469,22 +2550,12 @@ var LibraryGL = {
// ClientState/gl*Pointer
glEnableClientState: function(cap, disable) {
- var attrib;
- switch(cap) {
- case 0x8078: // GL_TEXTURE_COORD_ARRAY
- case 0x0de1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it
- attrib = GL.immediate.TEXTURE0 + GL.immediate.clientActiveTexture; break;
- case 0x8074: // GL_VERTEX_ARRAY
- attrib = GL.immediate.VERTEX; break;
- case 0x8075: // GL_NORMAL_ARRAY
- attrib = GL.immediate.NORMAL; break;
- case 0x8076: // GL_COLOR_ARRAY
- attrib = GL.immediate.COLOR; break;
- default:
+ var attrib = GLEmulation.getAttributeFromCapability(cap);
+ if (attrib === null) {
#if ASSERTIONS
- Module.printErr('WARNING: unhandled clientstate: ' + cap);
+ Module.printErr('WARNING: unhandled clientstate: ' + cap);
#endif
- return;
+ return;
}
if (disable && GL.immediate.enabledClientAttributes[attrib]) {
GL.immediate.enabledClientAttributes[attrib] = false;
@@ -2776,11 +2847,81 @@ var LibraryGL = {
glTexCoord3f: function() { throw 'glTexCoord3f: TODO' },
glGetTexLevelParameteriv: function() { throw 'glGetTexLevelParameteriv: TODO' },
- // signatures of simple pass-through functions, see later
- glActiveTexture__sig: 'vi',
+ glShadeModel: function() { Runtime.warnOnce('TODO: glShadeModel') },
+
+ glVertexAttribPointer__sig: 'viiiiii',
+ glVertexAttribPointer: function(index, size, type, normalized, stride, ptr) {
+#if FULL_ES2
+ if (!GL.currArrayBuffer) {
+ GL.clientBuffers[index] = { size: size, type: type, normalized: normalized, stride: stride, ptr: ptr };
+ return;
+ }
+
+ GL.clientBuffers[index] = null;
+#endif
+ Module.ctx.vertexAttribPointer(index, size, type, normalized, stride, ptr);
+ },
+
glEnableVertexAttribArray__sig: 'vi',
+ glEnableVertexAttribArray: function(index) {
+#if FULL_ES2
+ GL.enabledClientBuffers[index] = true;
+#endif
+ Module.ctx.enableVertexAttribArray(index);
+ },
+
glDisableVertexAttribArray__sig: 'vi',
- glVertexAttribPointer__sig: 'viiiiii',
+ glDisableVertexAttribArray: function(index) {
+#if FULL_ES2
+ GL.enabledClientBuffers[index] = false;
+#endif
+ Module.ctx.disableVertexAttribArray(index);
+ },
+
+ glDrawArrays: function(mode, first, count) {
+#if FULL_ES2
+ // bind any client-side buffers
+ GL.preDrawHandleClientVertexAttribBindings(count);
+#endif
+
+ Module.ctx.drawArrays(mode, first, count);
+
+#if FULL_ES2
+ GL.postDrawHandleClientVertexAttribBindings();
+#endif
+ },
+
+ glDrawElements: function(mode, count, type, indices) {
+#if FULL_ES2
+ var buf;
+ if (!GL.currElementArrayBuffer) {
+ buf = Module.ctx.createBuffer();
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, buf);
+ Module.ctx.bufferData(Module.ctx.ELEMENT_ARRAY_BUFFER,
+ HEAPU8.subarray(indices, indices + GL.calcBufLength(1, type, 0, count)),
+ Module.ctx.DYNAMIC_DRAW);
+ // the index is now 0
+ indices = 0;
+ }
+
+ // bind any client-side buffers
+ GL.preDrawHandleClientVertexAttribBindings(count);
+#endif
+
+ Module.ctx.drawElements(mode, count, type, indices);
+
+#if FULL_ES2
+ GL.postDrawHandleClientVertexAttribBindings(count);
+
+ if (!GL.currElementArrayBuffer) {
+ Module.ctx.bindBuffer(Module.ctx.ELEMENT_ARRAY_BUFFER, null);
+ Module.ctx.deleteBuffer(buf);
+ }
+#endif
+ },
+
+ // signatures of simple pass-through functions, see later
+ glActiveTexture__sig: 'vi',
glCheckFramebufferStatus__sig: 'ii',
glRenderbufferStorage__sig: 'viiii',
@@ -2802,19 +2943,18 @@ var LibraryGL = {
};
// Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name
-[[0, 'shadeModel getError* finish flush'],
- [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear enableVertexAttribArray disableVertexAttribArray lineWidth clearStencil depthMask stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation sampleCoverage isEnabled*'],
+[[0, 'getError* finish flush'],
+ [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil depthMask stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation sampleCoverage isEnabled*'],
[2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset'],
- [3, 'texParameteri texParameterf drawArrays vertexAttrib2f stencilFunc stencilOp'],
- [4, 'viewport clearColor scissor vertexAttrib3f colorMask drawElements renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'],
+ [3, 'texParameteri texParameterf vertexAttrib2f stencilFunc stencilOp'],
+ [4, 'viewport clearColor scissor vertexAttrib3f colorMask renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'],
[5, 'vertexAttrib4f'],
- [6, 'vertexAttribPointer'],
[8, 'copyTexImage2D copyTexSubImage2D']].forEach(function(data) {
var num = data[0];
var names = data[1];
var args = range(num).map(function(i) { return 'x' + i }).join(', ');
- var plainStub = '(function(' + args + ') { ' + (num > 0 ? 'Module.ctx.NAME(' + args + ')' : '') + ' })';
- var returnStub = '(function(' + args + ') { ' + (num > 0 ? 'return Module.ctx.NAME(' + args + ')' : '') + ' })';
+ var plainStub = '(function(' + args + ') { Module.ctx.NAME(' + args + ') })';
+ var returnStub = '(function(' + args + ') { return Module.ctx.NAME(' + args + ') })';
names.split(' ').forEach(function(name) {
var stub = plainStub;
if (name[name.length-1] == '*') {
@@ -2847,5 +2987,10 @@ LibraryGL.$GLEmulation__deps.push(function() {
for (var func in Functions.getIndex.tentative) Functions.getIndex(func);
});
+if (FORCE_GL_EMULATION) {
+ LibraryGL.glDrawElements__deps = LibraryGL.glDrawElements__deps.concat('$GLEmulation');
+ LibraryGL.glDrawArrays__deps = LibraryGL.glDrawArrays__deps.concat('$GLEmulation');
+}
+
mergeInto(LibraryManager.library, LibraryGL);
diff --git a/src/library_sdl.js b/src/library_sdl.js
index e02e1e62..96ae6fa2 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -44,6 +44,8 @@ var LibrarySDL = {
ctrlKey: false,
altKey: false,
+ textInput: false,
+
startTime: null,
mouseX: 0,
mouseY: 0,
@@ -173,6 +175,11 @@ var LibrarySDL = {
['i16', 'mod'],
['i32', 'unicode']
]),
+ TextInputEvent: Runtime.generateStructInfo([
+ ['i32', 'type'],
+ ['i32', 'windowID'],
+ ['b256', 'text'],
+ ]),
MouseMotionEvent: Runtime.generateStructInfo([
['i32', 'type'],
['i32', 'windowID'],
@@ -373,7 +380,7 @@ var LibrarySDL = {
}
}
// fall through
- case 'keydown': case 'keyup': case 'mousedown': case 'mouseup': case 'DOMMouseScroll': case 'mousewheel':
+ case 'keydown': case 'keyup': case 'keypress': case 'mousedown': case 'mouseup': case 'DOMMouseScroll': case 'mousewheel':
if (event.type == 'DOMMouseScroll' || event.type == 'mousewheel') {
var button = (event.type == 'DOMMouseScroll' ? event.detail : -event.wheelDelta) > 0 ? 4 : 3;
var event2 = {
@@ -397,6 +404,10 @@ var LibrarySDL = {
SDL.DOMButtons[event.button] = 0;
}
+ if (event.type == 'keypress' && !SDL.textInput) {
+ break;
+ }
+
SDL.events.push(event);
if (SDL.events.length >= 10000) {
Module.printErr('SDL event queue full, dropping earliest event');
@@ -476,6 +487,15 @@ var LibrarySDL = {
break;
}
+ case 'keypress': {
+ {{{ makeSetValue('ptr', 'SDL.structs.TextInputEvent.type', 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
+ // Not filling in windowID for now
+ var cStr = intArrayFromString(String.fromCharCode(event.charCode));
+ for (var i = 0; i < cStr.length; ++i) {
+ {{{ makeSetValue('ptr', 'SDL.structs.TextInputEvent.text + i', 'cStr[i]', 'i8') }}};
+ }
+ break;
+ }
case 'mousedown': case 'mouseup':
if (event.type == 'mousedown') {
// SDL_BUTTON(x) is defined as (1 << ((x)-1)). SDL buttons are 1-3,
@@ -618,6 +638,7 @@ var LibrarySDL = {
// Initialize this structure carefully for closure
SDL.DOMEventToSDLEvent['keydown'] = 0x300 /* SDL_KEYDOWN */;
SDL.DOMEventToSDLEvent['keyup'] = 0x301 /* SDL_KEYUP */;
+ SDL.DOMEventToSDLEvent['keypress'] = 0x303 /* SDL_TEXTINPUT */;
SDL.DOMEventToSDLEvent['mousedown'] = 0x401 /* SDL_MOUSEBUTTONDOWN */;
SDL.DOMEventToSDLEvent['mouseup'] = 0x402 /* SDL_MOUSEBUTTONUP */;
SDL.DOMEventToSDLEvent['mousemove'] = 0x400 /* SDL_MOUSEMOTION */;
@@ -1175,14 +1196,20 @@ var LibrarySDL = {
SDL_CondWait: function() {},
SDL_DestroyCond: function() {},
- SDL_StartTextInput: function() {}, // TODO
- SDL_StopTextInput: function() {}, // TODO
+ SDL_StartTextInput: function() {
+ SDL.textInput = true;
+ },
+ SDL_StopTextInput: function() {
+ SDL.textInput = false;
+ },
// SDL Mixer
Mix_Init: function(flags) {
+ if (!flags) return 0;
return 8; /* MIX_INIT_OGG */
},
+ Mix_Quit: function(){},
Mix_OpenAudio: function(frequency, format, channels, chunksize) {
SDL.allocateChannels(32);
@@ -1288,6 +1315,8 @@ var LibrarySDL = {
// the browser has already preloaded the audio file.
var channelInfo = SDL.channels[channel];
channelInfo.audio = audio = audio.cloneNode(true);
+ audio.numChannels = info.audio.numChannels;
+ audio.frequency = info.audio.frequency;
if (SDL.channelFinished) {
audio['onended'] = function() { // TODO: cache these
Runtime.getFuncWrapper(SDL.channelFinished, 'vi')(channel);
diff --git a/src/modules.js b/src/modules.js
index 695abbe7..afdbc21e 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -179,7 +179,16 @@ var Variables = {
globals: {},
indexedGlobals: {}, // for indexed globals, ident ==> index
// Used in calculation of indexed globals
- nextIndexedOffset: 0
+ nextIndexedOffset: 0,
+
+ resolveAliasToIdent: function(ident) {
+ while (1) {
+ var varData = Variables.globals[ident];
+ if (!(varData && varData.targetIdent)) break;
+ ident = varData.targetIdent; // might need to eval to turn (6) into 6
+ }
+ return ident;
+ },
};
var Types = {
@@ -330,12 +339,23 @@ var Functions = {
}
}
}
+ if (table.length > 20) {
+ // add some newlines in the table, for readability
+ var j = 10;
+ while (j+10 < table.length) {
+ table[j] += '\n';
+ j += 10;
+ }
+ }
var indices = table.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the parent's function table.
tables[t] = Functions.getTable(t) + '.push.apply(' + Functions.getTable(t) + ', [' + indices + ']);\n';
} else {
tables[t] = 'var ' + Functions.getTable(t) + ' = [' + indices + '];\n';
+ if (SAFE_DYNCALLS) {
+ tables[t] += 'var FUNCTION_TABLE_NAMES = ' + JSON.stringify(table).replace(/\n/g, '').replace(/,0/g, ',0\n') + ';\n';
+ }
}
}
if (!generated && !ASM_JS) {
diff --git a/src/parseTools.js b/src/parseTools.js
index 357d33a1..7f4f3a18 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -78,6 +78,7 @@ function toNiceIdent(ident) {
assert(ident);
if (parseFloat(ident) == ident) return ident;
if (ident == 'null') return '0'; // see parseNumerical
+ if (ident == 'undef') return '0';
return ident.replace('%', '$').replace(/["&\\ \.@:<>,\*\[\]\(\)-]/g, '_');
}
@@ -691,7 +692,7 @@ function makeCopyI64(value) {
function parseArbitraryInt(str, bits) {
// We parse the string into a vector of digits, base 10. This is convenient to work on.
- assert(bits % 32 == 0 || ('i' + (bits % 32)) in Runtime.INT_TYPES, 'Arbitrary-sized ints must tails that are of legal size');
+ assert(bits > 0); // NB: we don't check that the value in str can fit in this amount of bits
function str2vec(s) { // index 0 is the highest value
var ret = [];
@@ -984,18 +985,24 @@ function checkSafeHeap() {
function getHeapOffset(offset, type, forceAsm) {
if (USE_TYPED_ARRAYS !== 2) {
return offset;
- } else {
- if (Runtime.getNativeFieldSize(type) > 4) {
- type = 'i32'; // XXX we emulate 64-bit values as 32
- }
- var shifts = Math.log(Runtime.getNativeTypeSize(type))/Math.LN2;
- offset = '(' + offset + ')';
- if (shifts != 0) {
- return '(' + offset + '>>' + shifts + ')';
+ }
+
+ if (Runtime.getNativeFieldSize(type) > 4) {
+ type = 'i32'; // XXX we emulate 64-bit values as 32
+ }
+
+ var sz = Runtime.getNativeTypeSize(type);
+ var shifts = Math.log(sz)/Math.LN2;
+ offset = '(' + offset + ')';
+ if (shifts != 0) {
+ if (CHECK_HEAP_ALIGN) {
+ return '(CHECK_ALIGN_' + sz + '(' + offset + ')>>' + shifts + ')';
} else {
- // we need to guard against overflows here, HEAP[U]8 expects a guaranteed int
- return isJSVar(offset) ? offset : '(' + offset + '|0)';
+ return '(' + offset + '>>' + shifts + ')';
}
+ } else {
+ // we need to guard against overflows here, HEAP[U]8 expects a guaranteed int
+ return isJSVar(offset) ? offset : '(' + offset + '|0)';
}
}
@@ -1364,11 +1371,15 @@ var TWO_TWENTY = Math.pow(2, 20);
function getFastValue(a, op, b, type) {
a = a.toString();
b = b.toString();
+ a = a == 'true' ? '1' : (a == 'false' ? '0' : a);
+ b = b == 'true' ? '1' : (b == 'false' ? '0' : b);
if (isNumber(a) && isNumber(b)) {
if (op == 'pow') {
return Math.pow(a, b).toString();
} else {
- return eval(a + op + '(' + b + ')').toString(); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
+ var value = eval(a + op + '(' + b + ')'); // parens protect us from "5 - -12" being seen as "5--12" which is "(5--)12"
+ if (op == '/' && type in Runtime.INT_TYPES) value = value|0; // avoid emitting floats
+ return value.toString();
}
}
if (op == 'pow') {
@@ -1548,7 +1559,7 @@ function makePointer(slab, pos, allocator, type, ptr) {
var ret = '';
var index = 0;
while (index < array.length) {
- ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')' : '');
+ ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : '');
index += chunkSize;
}
return ret;
@@ -1829,9 +1840,10 @@ function makeSignOp(value, type, op, force, ignore) {
if (!CHECK_SIGNS || ignore) {
if (bits === 32) {
if (op === 're') {
- return '((' + value + ')|0)';
+ return '(' + getFastValue(value, '|', '0') + ')';
} else {
- return '((' + value + ')>>>0)';
+
+ return '(' + getFastValue(value, '>>>', '0') + ')';
// Alternatively, we can consider the lengthier
// return makeInlineCalculation('VALUE >= 0 ? VALUE : ' + Math.pow(2, bits) + ' + VALUE', value, 'tempBigInt');
// which does not always turn us into a 32-bit *un*signed value
@@ -1840,7 +1852,7 @@ function makeSignOp(value, type, op, force, ignore) {
if (op === 're') {
return makeInlineCalculation('(VALUE << ' + (32-bits) + ') >> ' + (32-bits), value, 'tempInt');
} else {
- return '((' + value + ')&' + (Math.pow(2, bits)-1) + ')';
+ return '(' + getFastValue(value, '&', Math.pow(2, bits)-1) + ')';
}
} else { // bits > 32
if (op === 're') {
@@ -2191,7 +2203,6 @@ function processMathop(item) {
case 'ne': case 'eq': {
// We must sign them, so we do not compare -1 to 255 (could have unsigned them both too)
// since LLVM tells us if <=, >= etc. comparisons are signed, but not == and !=.
- assert(paramTypes[0] == paramTypes[1]);
idents[0] = makeSignOp(idents[0], paramTypes[0], 're');
idents[1] = makeSignOp(idents[1], paramTypes[1], 're');
return idents[0] + (variant === 'eq' ? '==' : '!=') + idents[1];
diff --git a/src/preamble.js b/src/preamble.js
index a7731e7f..9bc68d8f 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -150,6 +150,25 @@ function SAFE_HEAP_COPY_HISTORY(dest, src) {
//==========================================
#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
@@ -251,11 +270,9 @@ Module["ccall"] = ccall;
// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
function getCFunc(ident) {
try {
- var func = eval('_' + ident);
+ var func = globalScope['Module']['_' + ident]; // closure exported function
+ if (!func) func = eval('_' + ident); // explicit lookup
} catch(e) {
- try {
- func = globalScope['Module']['_' + ident]; // closure exported function
- } catch(e) {}
}
assert(func, 'Cannot call unknown function ' + ident + ' (perhaps LLVM optimizations or closure removed it?)');
return func;
@@ -395,14 +412,6 @@ Module['ALLOC_STACK'] = ALLOC_STACK;
Module['ALLOC_STATIC'] = ALLOC_STATIC;
Module['ALLOC_NONE'] = ALLOC_NONE;
-// Simple unoptimized memset - necessary during startup
-var _memset = function(ptr, value, num) {
- var stop = ptr + num;
- while (ptr < stop) {
- {{{ makeSetValue('ptr++', 0, 'value', 'i8', null, true) }}};
- }
-}
-
// 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
@@ -436,7 +445,18 @@ function allocate(slab, types, allocator, ptr) {
}
if (zeroinit) {
- _memset(ret, 0, size);
+ 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;
}
@@ -447,7 +467,7 @@ function allocate(slab, types, allocator, ptr) {
}
#endif
- var i = 0, type;
+ var i = 0, type, typeSize, previousType;
while (i < size) {
var curr = slab[i];
@@ -469,7 +489,13 @@ function allocate(slab, types, allocator, ptr) {
#endif
setValue(ret+i, curr, type);
- i += Runtime.getNativeTypeSize(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;
@@ -543,6 +569,7 @@ function enlargeMemory() {
while (TOTAL_MEMORY <= STATICTOP) { // Simple heuristic. Override enlargeMemory() if your program has something more optimal for it
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 == 1
var oldIHEAP = IHEAP;
Module['HEAP'] = Module['IHEAP'] = HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index ae8577b1..1a7acc15 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -909,48 +909,54 @@ void Relooper::Calculate(Block *Entry) {
}
std::stack<Shape*> &LoopStack = *((std::stack<Shape*>*)Closure);
- SHAPE_SWITCH(Root, {
- MultipleShape *Fused = Shape::IsMultiple(Root->Next);
- // If we are fusing a Multiple with a loop into this Simple, then visit it now
- if (Fused && Fused->NeedLoop) {
- LoopStack.push(Fused);
- RECURSE_MULTIPLE_MANUAL(FindLabeledLoops, Fused);
- }
- for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
- Block *Target = iter->first;
- Branch *Details = iter->second;
- if (Details->Type != Branch::Direct) {
- assert(LoopStack.size() > 0);
- if (Details->Ancestor != LoopStack.top()) {
- LabeledShape *Labeled = Shape::IsLabeled(Details->Ancestor);
- Labeled->Labeled = true;
- Details->Labeled = true;
- } else {
- Details->Labeled = false;
+ Shape *Next = Root;
+ while (Next) {
+ Root = Next;
+ Next = NULL;
+
+ SHAPE_SWITCH(Root, {
+ MultipleShape *Fused = Shape::IsMultiple(Root->Next);
+ // If we are fusing a Multiple with a loop into this Simple, then visit it now
+ if (Fused && Fused->NeedLoop) {
+ LoopStack.push(Fused);
+ RECURSE_MULTIPLE_MANUAL(FindLabeledLoops, Fused);
+ }
+ for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) {
+ Block *Target = iter->first;
+ Branch *Details = iter->second;
+ if (Details->Type != Branch::Direct) {
+ assert(LoopStack.size() > 0);
+ if (Details->Ancestor != LoopStack.top()) {
+ LabeledShape *Labeled = Shape::IsLabeled(Details->Ancestor);
+ Labeled->Labeled = true;
+ Details->Labeled = true;
+ } else {
+ Details->Labeled = false;
+ }
}
}
- }
- if (Fused && Fused->NeedLoop) {
- LoopStack.pop();
- if (Fused->Next) FindLabeledLoops(Fused->Next);
- } else {
- if (Root->Next) FindLabeledLoops(Root->Next);
- }
- }, {
- if (Multiple->NeedLoop) {
- LoopStack.push(Multiple);
- }
- RECURSE_MULTIPLE(FindLabeledLoops);
- if (Multiple->NeedLoop) {
+ if (Fused && Fused->NeedLoop) {
+ LoopStack.pop();
+ Next = Fused->Next;
+ } else {
+ Next = Root->Next;
+ }
+ }, {
+ if (Multiple->NeedLoop) {
+ LoopStack.push(Multiple);
+ }
+ RECURSE_MULTIPLE(FindLabeledLoops);
+ if (Multiple->NeedLoop) {
+ LoopStack.pop();
+ }
+ Next = Root->Next;
+ }, {
+ LoopStack.push(Loop);
+ RECURSE_LOOP(FindLabeledLoops);
LoopStack.pop();
- }
- if (Root->Next) FindLabeledLoops(Root->Next);
- }, {
- LoopStack.push(Loop);
- RECURSE_LOOP(FindLabeledLoops);
- LoopStack.pop();
- if (Root->Next) FindLabeledLoops(Root->Next);
- });
+ Next = Root->Next;
+ });
+ }
if (First) {
delete (std::stack<Shape*>*)Closure;
diff --git a/src/relooper/test.txt b/src/relooper/test.txt
index 12d0ef39..b7c8794d 100644
--- a/src/relooper/test.txt
+++ b/src/relooper/test.txt
@@ -54,7 +54,7 @@ while(1) {
// code 2
if (!($2)) {
var $x_1 = $x_0;
- label = 18;
+ label = 19;
break;
}
// code 3
@@ -64,7 +64,7 @@ while(1) {
var $i_0 = $7;var $x_0 = $5;
}
}
-if (label == 18) {
+if (label == 19) {
// code 7
}
// code 4
diff --git a/src/relooper/test2.txt b/src/relooper/test2.txt
index a847e806..c77ce491 100644
--- a/src/relooper/test2.txt
+++ b/src/relooper/test2.txt
@@ -1,11 +1,12 @@
ep
-L1:
-if (ep -> LBB1) {
- LBB1
- if (!(LBB1 -> LBB2)) {
- break L1;
+do {
+ if (ep -> LBB1) {
+ LBB1
+ if (!(LBB1 -> LBB2)) {
+ break;
+ }
+ LBB2
}
- LBB2
-}
+} while(0);
LBB3
diff --git a/src/relooper/test3.txt b/src/relooper/test3.txt
index 7d06f06a..696542ef 100644
--- a/src/relooper/test3.txt
+++ b/src/relooper/test3.txt
@@ -1,25 +1,27 @@
ep
-L1:
-if (ep -> LBB1) {
- LBB1
- if (!(LBB1 -> LBB2)) {
- break L1;
+do {
+ if (ep -> LBB1) {
+ LBB1
+ if (!(LBB1 -> LBB2)) {
+ break;
+ }
+ LBB2
}
- LBB2
-}
+} while(0);
LBB3
-L5:
-if (LBB3 -> LBB4) {
- LBB4
- if (!(LBB4 -> LBB5)) {
- break L5;
- }
- while(1) {
- LBB5
- if (LBB5 -> LBB6) {
- break L5;
+L5: do {
+ if (LBB3 -> LBB4) {
+ LBB4
+ if (!(LBB4 -> LBB5)) {
+ break;
+ }
+ while(1) {
+ LBB5
+ if (LBB5 -> LBB6) {
+ break L5;
+ }
}
}
-}
+} while(0);
LBB6
diff --git a/src/relooper/test4.txt b/src/relooper/test4.txt
index 2ab3265a..f0bfb972 100644
--- a/src/relooper/test4.txt
+++ b/src/relooper/test4.txt
@@ -1,16 +1,17 @@
//19
-L1:
-if ( 1 ) {
- //20
- if (!( 1 )) {
+do {
+ if ( 1 ) {
+ //20
+ if (!( 1 )) {
+ label = 4;
+ break;
+ }
+ //21
+ break;
+ } else {
label = 4;
- break L1;
}
- //21
- break L1;
-} else {
- label = 4;
-}
+} while(0);
if (label == 4) {
//22
}
diff --git a/src/relooper/test6.txt b/src/relooper/test6.txt
index 0ec7e666..c5effd08 100644
--- a/src/relooper/test6.txt
+++ b/src/relooper/test6.txt
@@ -1,11 +1,12 @@
//0
-L1:
-if (check(0)) {
- //1
- if (!(check(1))) {
- break L1;
+do {
+ if (check(0)) {
+ //1
+ if (!(check(1))) {
+ break;
+ }
+ //2
}
- //2
-}
+} while(0);
//3
diff --git a/src/relooper/test_debug.txt b/src/relooper/test_debug.txt
index 02377fb7..1c7d0508 100644
--- a/src/relooper/test_debug.txt
+++ b/src/relooper/test_debug.txt
@@ -83,13 +83,14 @@ int main() {
// === Optimizing shapes ===
// Fusing Multiple to Simple
ep
-L1:
-if (ep -> LBB1) {
- LBB1
- if (!(LBB1 -> LBB2)) {
- break L1;
+do {
+ if (ep -> LBB1) {
+ LBB1
+ if (!(LBB1 -> LBB2)) {
+ break;
+ }
+ LBB2
}
- LBB2
-}
+} while(0);
LBB3
diff --git a/src/relooper/test_fuzz1.txt b/src/relooper/test_fuzz1.txt
index 09edb594..5122257e 100644
--- a/src/relooper/test_fuzz1.txt
+++ b/src/relooper/test_fuzz1.txt
@@ -3,12 +3,13 @@
print('entry'); var label; var state; var decisions = [4, 1, 7, 2, 6, 6, 8]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] }
print(5); state = check();
print(6); state = check();
-L3:
-if (state == 7) {
- print(7); state = check();
- label = 3;
- break L3;
-}
+do {
+ if (state == 7) {
+ print(7); state = check();
+ label = 3;
+ break;
+ }
+} while(0);
L5: while(1) {
if (label == 3) {
label = 0;
diff --git a/src/relooper/test_fuzz5.txt b/src/relooper/test_fuzz5.txt
index 7c795d53..9548205c 100644
--- a/src/relooper/test_fuzz5.txt
+++ b/src/relooper/test_fuzz5.txt
@@ -3,21 +3,22 @@
print('entry'); var label; var state; var decisions = [133, 98, 134, 143, 162, 187, 130, 87, 91, 49, 102, 47, 9, 132, 179, 176, 157, 25, 64, 161, 57, 107, 16, 167, 185, 45, 191, 180, 23, 131]; var index = 0; function check() { if (index == decisions.length) throw 'HALT'; return decisions[index++] }
L1: while(1) {
print(7); state = check();
- L3:
- if (state % 3 == 1) {
- label = 3;
- } else if (state % 3 == 0) {
- print(8); state = check();
- if (state % 2 == 0) {
- label = 5;
- break L3;
+ do {
+ if (state % 3 == 1) {
+ label = 3;
+ } else if (state % 3 == 0) {
+ print(8); state = check();
+ if (state % 2 == 0) {
+ label = 5;
+ break;
+ } else {
+ label = 7;
+ break;
+ }
} else {
- label = 7;
- break L3;
+ break L1;
}
- } else {
- break L1;
- }
+ } while(0);
while(1) {
if (label == 3) {
label = 0;
diff --git a/src/relooper/test_inf.txt b/src/relooper/test_inf.txt
index 3e292433..379d2083 100644
--- a/src/relooper/test_inf.txt
+++ b/src/relooper/test_inf.txt
@@ -5,34 +5,35 @@ if (uint(i4) >= uint(i5)) {
code 1
}
code 3
-L5:
-if (!(i2 == 0)) {
- code 4
- while(1) {
- code 5
- if (uint(i6) >= uint(i7)) {
- code 7
- } else {
- code 6
- }
- code 8
- if (uint(i6) >= uint(i7)) {
- code 10
- } else {
- code 9
- }
- code 11
- if (uint(i5) >= uint(i6)) {
- code 13
- } else {
- code 12
- }
- code 14
- if (!(i2 != 0)) {
- break L5;
+L5: do {
+ if (!(i2 == 0)) {
+ code 4
+ while(1) {
+ code 5
+ if (uint(i6) >= uint(i7)) {
+ code 7
+ } else {
+ code 6
+ }
+ code 8
+ if (uint(i6) >= uint(i7)) {
+ code 10
+ } else {
+ code 9
+ }
+ code 11
+ if (uint(i5) >= uint(i6)) {
+ code 13
+ } else {
+ code 12
+ }
+ code 14
+ if (!(i2 != 0)) {
+ break L5;
+ }
}
}
-}
+} while(0);
code 15
if (uint(i4) >= uint(i5)) {
code 17
@@ -40,178 +41,179 @@ if (uint(i4) >= uint(i5)) {
code 16
}
code 18
-L26:
-if (!(i2 == 0)) {
- code 19
- while(1) {
- code 20
- if (uint(i5) >= uint(i6)) {
- code 22
- } else {
- code 21
- }
- code 23
- if (uint(i5) >= uint(i6)) {
- code 25
- } else {
- code 24
- }
- code 26
- if (uint(i5) >= uint(i6)) {
- code 28
- } else {
- code 27
- }
- code 29
- if (uint(i5) >= uint(i6)) {
- code 31
- } else {
- code 30
- }
- code 32
- if (uint(i5) >= uint(i6)) {
- code 34
- } else {
- code 33
- }
- code 35
- if (uint(i5) >= uint(i6)) {
- code 37
- } else {
- code 36
- }
- code 38
- if (uint(i5) >= uint(i6)) {
- code 40
- } else {
- code 39
- }
- code 41
- if (uint(i5) >= uint(i6)) {
- code 43
- } else {
- code 42
- }
- code 44
- if (uint(i5) >= uint(i6)) {
- code 46
- } else {
- code 45
- }
- code 47
- if (uint(i5) >= uint(i6)) {
- code 49
- } else {
- code 48
- }
- code 50
- if (uint(i5) >= uint(i6)) {
- code 52
- } else {
- code 51
- }
- code 53
- if (uint(i5) >= uint(i6)) {
- code 55
- } else {
- code 54
- }
- code 56
- if (uint(i5) >= uint(i6)) {
- code 58
- } else {
- code 57
- }
- code 59
- if (uint(i5) >= uint(i6)) {
- code 61
- } else {
- code 60
- }
- code 62
- if (uint(i5) >= uint(i6)) {
- code 64
- } else {
- code 63
- }
- code 65
- if (uint(i5) >= uint(i6)) {
- code 67
- } else {
- code 66
- }
- code 68
- if (uint(i5) >= uint(i6)) {
- code 70
- } else {
- code 69
- }
- code 71
- if (uint(i5) >= uint(i6)) {
- code 73
- } else {
- code 72
- }
- code 74
- if (uint(i5) >= uint(i6)) {
- code 76
- } else {
- code 75
- }
- code 77
- if (uint(i5) >= uint(i6)) {
- code 79
- } else {
- code 78
- }
- code 80
- if (uint(i5) >= uint(i6)) {
- code 82
- } else {
- code 81
- }
- code 83
- if (uint(i5) >= uint(i6)) {
- code 85
- } else {
- code 84
- }
- code 86
- if (uint(i5) >= uint(i6)) {
- code 88
- } else {
- code 87
- }
- code 89
- if (uint(i5) >= uint(i6)) {
- code 91
- } else {
- code 90
- }
- code 92
- if (uint(i5) >= uint(i6)) {
- code 94
- } else {
- code 93
- }
- code 95
- if (uint(i5) >= uint(i6)) {
- code 97
- } else {
- code 96
- }
- code 98
- if (uint(i5) >= uint(i6)) {
- code 100
- } else {
- code 99
- }
- code 101
- if (!(i2 != 0)) {
- break L26;
+L26: do {
+ if (!(i2 == 0)) {
+ code 19
+ while(1) {
+ code 20
+ if (uint(i5) >= uint(i6)) {
+ code 22
+ } else {
+ code 21
+ }
+ code 23
+ if (uint(i5) >= uint(i6)) {
+ code 25
+ } else {
+ code 24
+ }
+ code 26
+ if (uint(i5) >= uint(i6)) {
+ code 28
+ } else {
+ code 27
+ }
+ code 29
+ if (uint(i5) >= uint(i6)) {
+ code 31
+ } else {
+ code 30
+ }
+ code 32
+ if (uint(i5) >= uint(i6)) {
+ code 34
+ } else {
+ code 33
+ }
+ code 35
+ if (uint(i5) >= uint(i6)) {
+ code 37
+ } else {
+ code 36
+ }
+ code 38
+ if (uint(i5) >= uint(i6)) {
+ code 40
+ } else {
+ code 39
+ }
+ code 41
+ if (uint(i5) >= uint(i6)) {
+ code 43
+ } else {
+ code 42
+ }
+ code 44
+ if (uint(i5) >= uint(i6)) {
+ code 46
+ } else {
+ code 45
+ }
+ code 47
+ if (uint(i5) >= uint(i6)) {
+ code 49
+ } else {
+ code 48
+ }
+ code 50
+ if (uint(i5) >= uint(i6)) {
+ code 52
+ } else {
+ code 51
+ }
+ code 53
+ if (uint(i5) >= uint(i6)) {
+ code 55
+ } else {
+ code 54
+ }
+ code 56
+ if (uint(i5) >= uint(i6)) {
+ code 58
+ } else {
+ code 57
+ }
+ code 59
+ if (uint(i5) >= uint(i6)) {
+ code 61
+ } else {
+ code 60
+ }
+ code 62
+ if (uint(i5) >= uint(i6)) {
+ code 64
+ } else {
+ code 63
+ }
+ code 65
+ if (uint(i5) >= uint(i6)) {
+ code 67
+ } else {
+ code 66
+ }
+ code 68
+ if (uint(i5) >= uint(i6)) {
+ code 70
+ } else {
+ code 69
+ }
+ code 71
+ if (uint(i5) >= uint(i6)) {
+ code 73
+ } else {
+ code 72
+ }
+ code 74
+ if (uint(i5) >= uint(i6)) {
+ code 76
+ } else {
+ code 75
+ }
+ code 77
+ if (uint(i5) >= uint(i6)) {
+ code 79
+ } else {
+ code 78
+ }
+ code 80
+ if (uint(i5) >= uint(i6)) {
+ code 82
+ } else {
+ code 81
+ }
+ code 83
+ if (uint(i5) >= uint(i6)) {
+ code 85
+ } else {
+ code 84
+ }
+ code 86
+ if (uint(i5) >= uint(i6)) {
+ code 88
+ } else {
+ code 87
+ }
+ code 89
+ if (uint(i5) >= uint(i6)) {
+ code 91
+ } else {
+ code 90
+ }
+ code 92
+ if (uint(i5) >= uint(i6)) {
+ code 94
+ } else {
+ code 93
+ }
+ code 95
+ if (uint(i5) >= uint(i6)) {
+ code 97
+ } else {
+ code 96
+ }
+ code 98
+ if (uint(i5) >= uint(i6)) {
+ code 100
+ } else {
+ code 99
+ }
+ code 101
+ if (!(i2 != 0)) {
+ break L26;
+ }
}
}
-}
+} while(0);
code 102
if (uint(i4) >= uint(i5)) {
code 104
@@ -219,136 +221,137 @@ if (uint(i4) >= uint(i5)) {
code 103
}
code 105
-L143:
-if (!(i2 == 0)) {
- code 106
- while(1) {
- code 107
- if (uint(i5) >= uint(i6)) {
- code 109
- } else {
- code 108
- }
- code 110
- if (uint(i5) >= uint(i6)) {
- code 112
- } else {
- code 111
- }
- code 113
- if (uint(i5) >= uint(i6)) {
- code 115
- } else {
- code 114
- }
- code 116
- if (uint(i5) >= uint(i6)) {
- code 118
- } else {
- code 117
- }
- code 119
- if (uint(i5) >= uint(i6)) {
- code 121
- } else {
- code 120
- }
- code 122
- if (uint(i5) >= uint(i6)) {
- code 124
- } else {
- code 123
- }
- code 125
- if (uint(i5) >= uint(i6)) {
- code 127
- } else {
- code 126
- }
- code 128
- if (uint(i5) >= uint(i6)) {
- code 130
- } else {
- code 129
- }
- code 131
- if (uint(i5) >= uint(i6)) {
- code 133
- } else {
- code 132
- }
- code 134
- if (uint(i5) >= uint(i6)) {
- code 136
- } else {
- code 135
- }
- code 137
- if (uint(i5) >= uint(i6)) {
- code 139
- } else {
- code 138
- }
- code 140
- if (uint(i5) >= uint(i6)) {
- code 142
- } else {
- code 141
- }
- code 143
- if (uint(i5) >= uint(i6)) {
- code 145
- } else {
- code 144
- }
- code 146
- if (uint(i5) >= uint(i6)) {
- code 148
- } else {
- code 147
- }
- code 149
- if (uint(i5) >= uint(i6)) {
- code 151
- } else {
- code 150
- }
- code 152
- if (uint(i5) >= uint(i6)) {
- code 154
- } else {
- code 153
- }
- code 155
- if (uint(i5) >= uint(i6)) {
- code 157
- } else {
- code 156
- }
- code 158
- if (uint(i5) >= uint(i6)) {
- code 160
- } else {
- code 159
- }
- code 161
- if (uint(i5) >= uint(i6)) {
- code 163
- } else {
- code 162
- }
- code 164
- if (uint(i5) >= uint(i6)) {
- code 166
- } else {
- code 165
- }
- code 167
- if (!(i2 != 0)) {
- break L143;
+L143: do {
+ if (!(i2 == 0)) {
+ code 106
+ while(1) {
+ code 107
+ if (uint(i5) >= uint(i6)) {
+ code 109
+ } else {
+ code 108
+ }
+ code 110
+ if (uint(i5) >= uint(i6)) {
+ code 112
+ } else {
+ code 111
+ }
+ code 113
+ if (uint(i5) >= uint(i6)) {
+ code 115
+ } else {
+ code 114
+ }
+ code 116
+ if (uint(i5) >= uint(i6)) {
+ code 118
+ } else {
+ code 117
+ }
+ code 119
+ if (uint(i5) >= uint(i6)) {
+ code 121
+ } else {
+ code 120
+ }
+ code 122
+ if (uint(i5) >= uint(i6)) {
+ code 124
+ } else {
+ code 123
+ }
+ code 125
+ if (uint(i5) >= uint(i6)) {
+ code 127
+ } else {
+ code 126
+ }
+ code 128
+ if (uint(i5) >= uint(i6)) {
+ code 130
+ } else {
+ code 129
+ }
+ code 131
+ if (uint(i5) >= uint(i6)) {
+ code 133
+ } else {
+ code 132
+ }
+ code 134
+ if (uint(i5) >= uint(i6)) {
+ code 136
+ } else {
+ code 135
+ }
+ code 137
+ if (uint(i5) >= uint(i6)) {
+ code 139
+ } else {
+ code 138
+ }
+ code 140
+ if (uint(i5) >= uint(i6)) {
+ code 142
+ } else {
+ code 141
+ }
+ code 143
+ if (uint(i5) >= uint(i6)) {
+ code 145
+ } else {
+ code 144
+ }
+ code 146
+ if (uint(i5) >= uint(i6)) {
+ code 148
+ } else {
+ code 147
+ }
+ code 149
+ if (uint(i5) >= uint(i6)) {
+ code 151
+ } else {
+ code 150
+ }
+ code 152
+ if (uint(i5) >= uint(i6)) {
+ code 154
+ } else {
+ code 153
+ }
+ code 155
+ if (uint(i5) >= uint(i6)) {
+ code 157
+ } else {
+ code 156
+ }
+ code 158
+ if (uint(i5) >= uint(i6)) {
+ code 160
+ } else {
+ code 159
+ }
+ code 161
+ if (uint(i5) >= uint(i6)) {
+ code 163
+ } else {
+ code 162
+ }
+ code 164
+ if (uint(i5) >= uint(i6)) {
+ code 166
+ } else {
+ code 165
+ }
+ code 167
+ if (!(i2 != 0)) {
+ break L143;
+ }
}
}
-}
+} while(0);
code 168
if (uint(i4) >= uint(i5)) {
code 170
diff --git a/src/runtime.js b/src/runtime.js
index e902d27b..7f97da35 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -25,7 +25,7 @@ var RuntimeGenerator = {
sep = sep || ';';
if (USE_TYPED_ARRAYS === 2) 'STACKTOP = (STACKTOP + STACKTOP|0 % ' + ({{{ QUANTUM_SIZE }}} - (isNumber(size) ? Math.min(size, {{{ QUANTUM_SIZE }}}) : {{{ QUANTUM_SIZE }}})) + ')' + sep;
// The stack is always QUANTUM SIZE aligned, so we may not need to force alignment here
- var ret = RuntimeGenerator.alloc(size, 'STACK', INIT_STACK, sep, USE_TYPED_ARRAYS != 2 || (isNumber(size) && parseInt(size) % {{{ QUANTUM_SIZE }}} == 0));
+ var ret = RuntimeGenerator.alloc(size, 'STACK', false, sep, USE_TYPED_ARRAYS != 2 || (isNumber(size) && parseInt(size) % {{{ QUANTUM_SIZE }}} == 0));
if (ASSERTIONS) {
ret += sep + 'assert(STACKTOP|0 < STACK_MAX|0)';
}
@@ -45,7 +45,7 @@ var RuntimeGenerator = {
if (ASSERTIONS) {
ret += '; assert(STACKTOP < STACK_MAX)';
}
- if (INIT_STACK) {
+ if (false) {
ret += '; _memset(' + asmCoercion('__stackBase__', 'i32') + ', 0, ' + initial + ')';
}
return ret;
diff --git a/src/settings.js b/src/settings.js
index 7caa5b92..1bfcf92a 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -37,7 +37,6 @@ var VERBOSE = 0; // When set to 1, will generate more verbose output during comp
var INVOKE_RUN = 1; // Whether we will call run(). Disable if you embed the generated
// code in your own, and will call run() yourself at the right time
-var INIT_STACK = 0; // Whether to initialize memory on the stack to 0.
var INIT_HEAP = 0; // Whether to initialize memory anywhere other than the stack to 0.
var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlarge the stack, so this
// value must be large enough for the program's requirements. If
@@ -59,6 +58,8 @@ var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to al
// Code embetterments
var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables
var RELOOP = 0; // Recreate js native loops from llvm data
+var RELOOPER = 'relooper.js'; // Loads the relooper from this path relative to compiler.js
+
var USE_TYPED_ARRAYS = 2; // Use typed arrays for the heap. See https://github.com/kripken/emscripten/wiki/Code-Generation-Modes/
// 0 means no typed arrays are used.
// 1 has two heaps, IHEAP (int32) and FHEAP (double),
@@ -107,10 +108,11 @@ var SKIP_STACK_IN_SMALL = 1; // When enabled, does not push/pop the stack at all
// In particular, be careful with the autodebugger! (We do turn
// this off automatically in that case, though.)
var INLINE_LIBRARY_FUNCS = 1; // Will inline library functions that have __inline defined
-var INLINING_LIMIT = 50; // A limit on inlining. If 0, we will inline normally in LLVM and
+var INLINING_LIMIT = 0; // A limit on inlining. If 0, we will inline normally in LLVM and
// closure. If greater than 0, we will *not* inline in LLVM, and
// we will prevent inlining of functions of this size or larger
- // in closure.
+ // in closure. 50 is a reasonable setting if you do not want
+ // inlining
var CATCH_EXIT_CODE = 0; // If set, causes exit() to throw an exception object which is caught
// in a try..catch block and results in the exit status being
// returned from run(). If zero (the default), the program is just
@@ -128,6 +130,11 @@ var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give
// that 3 is the option you usually want here.
var SAFE_HEAP_LOG = 0; // Log out all SAFE_HEAP operations
+var CHECK_HEAP_ALIGN = 0; // Check heap accesses for alignment, but don't do as
+ // near extensive (or slow) checks as SAFE_HEAP.
+
+var SAFE_DYNCALLS = 0; // Show stack traces on missing function pointer/virtual method calls
+
var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js
var CORRUPTION_CHECK = 0; // When enabled, will emit a buffer area at the beginning and
@@ -161,6 +168,8 @@ var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you
var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, to allow tests to work (but adds overhead)
var GL_MAX_TEMP_BUFFER_SIZE = 2097152; // How large GL emulation temp buffers are
var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL emulation code
+var FULL_ES2 = 0; // Forces support for all GLES2 features, not just the WebGL-friendly subset.
+var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code.
var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catch exceptions. If the code you
// are compiling does not actually rely on catching exceptions (but the
@@ -327,6 +336,8 @@ var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i3
var NECESSARY_BLOCKADDRS = []; // List of (function, block) for all block addresses that are taken.
+var EMIT_GENERATED_FUNCTIONS = 0; // whether to emit the list of generated functions, needed for external JS optimization passes
+
// Compiler debugging options
var DEBUG_TAGS_SHOWING = [];
// Some useful items:
diff --git a/src/shell.html b/src/shell.html
index 3a0171de..4f39b26a 100644
--- a/src/shell.html
+++ b/src/shell.html
@@ -32,6 +32,7 @@
var element = document.getElementById('output');
element.value = ''; // clear browser cache
return function(text) {
+ text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
@@ -42,6 +43,7 @@
};
})(),
printErr: function(text) {
+ text = Array.prototype.slice.call(arguments).join(' ');
if (0) { // XXX disabled for safety typeof dump == 'function') {
dump(text + '\n'); // fast, straight to the real console
} else {