diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 29 | ||||
-rw-r--r-- | src/compiler.js | 15 | ||||
-rw-r--r-- | src/corruptionCheck.js | 98 | ||||
-rw-r--r-- | src/experimental/allow_loopvars_from_memsetcpy_inasm.diff | 97 | ||||
-rw-r--r-- | src/intertyper.js | 4 | ||||
-rw-r--r-- | src/jsifier.js | 63 | ||||
-rw-r--r-- | src/library.js | 481 | ||||
-rw-r--r-- | src/library_browser.js | 93 | ||||
-rw-r--r-- | src/library_egl.js | 41 | ||||
-rw-r--r-- | src/library_gc.js | 2 | ||||
-rw-r--r-- | src/library_gl.js | 761 | ||||
-rw-r--r-- | src/library_glut.js | 6 | ||||
-rw-r--r-- | src/library_sdl.js | 143 | ||||
-rw-r--r-- | src/long.js | 11 | ||||
-rw-r--r-- | src/modules.js | 22 | ||||
-rw-r--r-- | src/parseTools.js | 128 | ||||
-rw-r--r-- | src/preamble.js | 221 | ||||
-rw-r--r-- | src/relooper/Relooper.cpp | 156 | ||||
-rw-r--r-- | src/relooper/fuzzer.py | 4 | ||||
-rw-r--r-- | src/relooper/test2.txt | 15 | ||||
-rw-r--r-- | src/relooper/test3.txt | 38 | ||||
-rw-r--r-- | src/relooper/test4.txt | 21 | ||||
-rw-r--r-- | src/relooper/test6.txt | 15 | ||||
-rw-r--r-- | src/relooper/test_debug.txt | 15 | ||||
-rw-r--r-- | src/relooper/test_fuzz1.txt | 13 | ||||
-rw-r--r-- | src/relooper/test_fuzz5.txt | 27 | ||||
-rw-r--r-- | src/relooper/test_inf.txt | 651 | ||||
-rw-r--r-- | src/runtime.js | 40 | ||||
-rw-r--r-- | src/settings.js | 57 | ||||
-rw-r--r-- | src/shell.html | 11 |
30 files changed, 2088 insertions, 1190 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 1c53b76c..209e3140 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; @@ -223,6 +225,9 @@ function analyzer(data, sidePass) { for (var i = 0; i < item.params.length; i++) { if (item.params[i].type == 'i64') item.params[i].type = 'i32'; } + } else if (item.intertype == 'inttoptr') { + var input = item.params[0]; + if (input.type == 'i64') input.type = 'i32'; // inttoptr can only care about 32 bits anyhow since pointers are 32-bit } if (isIllegalType(item.valueType) || isIllegalType(item.type)) { isIllegal = true; @@ -285,7 +290,7 @@ function analyzer(data, sidePass) { var elements = getLegalParams([item.value], bits)[0]; var j = 0; elements.forEach(function(element) { - var tempVar = '$st$' + i + '$' + j; + var tempVar = '$st$' + (tempId++) + '$' + j; toAdd.push({ intertype: 'getelementptr', assignTo: tempVar, @@ -396,7 +401,7 @@ function analyzer(data, sidePass) { var j = 0; var toAdd = []; elements.forEach(function(element) { - var tempVar = '$st$' + i + '$' + j; + var tempVar = '$ld$' + (tempId++) + '$' + j; toAdd.push({ intertype: 'getelementptr', assignTo: tempVar, @@ -643,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'); @@ -681,9 +680,9 @@ function analyzer(data, sidePass) { params: [(signed && j + whole > sourceElements.length) ? signedKeepAlive : null], type: 'i32', }; - if (j == 0 && isUnsignedOp(value.op) && sourceBits < 32) { + if (j == 0 && sourceBits < 32) { // zext sign correction - result.ident = makeSignOp(result.ident, 'i' + sourceBits, 'un', 1, 1); + result.ident = makeSignOp(result.ident, 'i' + sourceBits, isUnsignedOp(value.op) ? 'un' : 're', 1, 1); } if (fraction != 0) { var other = { @@ -953,6 +952,7 @@ function analyzer(data, sidePass) { // Function parameters func.params.forEach(function(param) { if (param.intertype !== 'varargs') { + if (func.variables[param.ident]) warn('cannot have duplicate variable names: ' + param.ident); // toNiceIdent collisions? func.variables[param.ident] = { ident: param.ident, type: param.type, @@ -966,6 +966,7 @@ function analyzer(data, sidePass) { // Normal variables func.lines.forEach(function(item, i) { if (item.assignTo) { + if (func.variables[item.assignTo]) warn('cannot have duplicate variable names: ' + item.assignTo); // toNiceIdent collisions? var variable = func.variables[item.assignTo] = { ident: item.assignTo, type: item.type, @@ -1381,7 +1382,7 @@ function analyzer(data, sidePass) { var label = func.labels[i]; for (var j = 0; j < label.lines.length; j++) { var line = label.lines[j]; - if (line.intertype == 'call' && line.ident == setjmp) { + if ((line.intertype == 'call' || line.intertype == 'invoke') && line.ident == setjmp) { // Add a new label var oldIdent = label.ident; var newIdent = func.labelIdCounter++; diff --git a/src/compiler.js b/src/compiler.js index 25c306cf..3047daf1 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -160,12 +160,6 @@ if (SAFE_HEAP >= 2) { SAFE_HEAP_LINES = set(SAFE_HEAP_LINES); // for fast checking } -if (PGO) { // by default, correct everything during PGO - CORRECT_SIGNS = CORRECT_SIGNS || 1; - CORRECT_OVERFLOWS = CORRECT_OVERFLOWS || 1; - CORRECT_ROUNDINGS = CORRECT_ROUNDINGS || 1; -} - EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); @@ -178,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 || - !SKIP_STACK_IN_SMALL || SAFE_HEAP || PGO || PROFILE || !DISABLE_EXCEPTION_CATCHING) { + 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.'); } } @@ -204,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/corruptionCheck.js b/src/corruptionCheck.js new file mode 100644 index 00000000..315f5cf0 --- /dev/null +++ b/src/corruptionCheck.js @@ -0,0 +1,98 @@ + +// See settings.js, CORRUPTION_CHECK + +var CorruptionChecker = { + BUFFER_FACTOR: Math.round({{{ CORRUPTION_CHECK }}}), + + ptrs: {}, + checks: 0, + checkFrequency: 1, + + init: function() { + this.realMalloc = _malloc; + _malloc = Module['_malloc'] = this.malloc; + + this.realFree = _free; + _free = Module['_free'] = this.free; + + if (typeof _realloc != 'undefined') { + this.realRealloc = _realloc; + _realloc = Module['_realloc'] = this.realloc; + } + + __ATEXIT__.push({ func: function() { + Module.printErr('No corruption detected, ran ' + CorruptionChecker.checks + ' checks.'); + } }); + }, + malloc: function(size) { + if (size <= 0) size = 1; // malloc(0) sometimes happens - just allocate a larger area, no harm + CorruptionChecker.checkAll(); + size = (size+7)&(~7); + var allocation = CorruptionChecker.realMalloc(size*(1+2*CorruptionChecker.BUFFER_FACTOR)); + var ptr = allocation + size*CorruptionChecker.BUFFER_FACTOR; + assert(!CorruptionChecker.ptrs[ptr]); + CorruptionChecker.ptrs[ptr] = size; + CorruptionChecker.fillBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); + CorruptionChecker.fillBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); + //Module.printErr('malloc ' + size + ' ==> ' + [ptr, allocation]); + return ptr; + }, + free: function(ptr) { + if (!ptr) return; // ok to free(NULL), does nothing + CorruptionChecker.checkAll(); + var size = CorruptionChecker.ptrs[ptr]; + //Module.printErr('free ' + ptr + ' of size ' + size); + assert(size); + var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; + //Module.printErr('free ' + ptr + ' of size ' + size + ' and allocation ' + allocation); + delete CorruptionChecker.ptrs[ptr]; + CorruptionChecker.realFree(allocation); + }, + realloc: function(ptr, newSize) { + //Module.printErr('realloc ' + ptr + ' to size ' + newSize); + if (newSize <= 0) newSize = 1; // like in malloc + if (!ptr) return CorruptionChecker.malloc(newSize); // realloc(NULL, size) forwards to malloc according to the spec + var size = CorruptionChecker.ptrs[ptr]; + assert(size); + var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; + var newPtr = CorruptionChecker.malloc(newSize); + //Module.printErr('realloc ' + ptr + ' to size ' + newSize + ' is now ' + newPtr); + var newAllocation = newPtr + newSize*CorruptionChecker.BUFFER_FACTOR; + HEAPU8.set(HEAPU8.subarray(ptr, ptr + Math.min(size, newSize)), newPtr); + CorruptionChecker.free(ptr); + return newPtr; + }, + canary: function(x) { + return (x&127) + 10; + }, + fillBuffer: function(buffer, size) { + for (var x = buffer; x < buffer + size; x++) { + {{{ makeSetValue('x', 0, 'CorruptionChecker.canary(x)', 'i8') }}}; + } + }, + checkBuffer: function(buffer, size) { + for (var x = buffer; x < buffer + size; x++) { + if (({{{ makeGetValue('x', 0, 'i8') }}}&255) != CorruptionChecker.canary(x)) { + assert(0, 'Heap corruption detected!' + [x, buffer, size, {{{ makeGetValue('x', 0, 'i8') }}}&255, CorruptionChecker.canary(x)]); + } + } + }, + checkPtr: function(ptr) { + var size = CorruptionChecker.ptrs[ptr]; + assert(size); + var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; + CorruptionChecker.checkBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); + CorruptionChecker.checkBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); + }, + checkAll: function(force) { + CorruptionChecker.checks++; + if (!force && CorruptionChecker.checks % CorruptionChecker.checkFrequency != 0) return; + //Module.printErr('checking for corruption ' + (CorruptionChecker.checks/CorruptionChecker.checkFrequency)); + for (var ptr in CorruptionChecker.ptrs) { + CorruptionChecker.checkPtr(ptr, false); + } + }, +}; + +CorruptionChecker.init(); + diff --git a/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff b/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff new file mode 100644 index 00000000..a2dde7da --- /dev/null +++ b/src/experimental/allow_loopvars_from_memsetcpy_inasm.diff @@ -0,0 +1,97 @@ +commit a61ef3dbbaf7333ad67fca29c0aad5bcc99b653a +Author: Alon Zakai <alonzakai@gmail.com> +Date: Wed Mar 6 18:18:03 2013 -0800 + + handle new vars in asm code, such as the loop vars from memset/memcpy loops + +diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js +index f2dc516..65059e8 100644 +--- a/tools/js-optimizer.js ++++ b/tools/js-optimizer.js +@@ -1321,7 +1321,7 @@ function normalizeAsm(func) { + var name = v[0]; + var value = v[1]; + if (!(name in data.vars)) { +- assert(value[0] == 'num' || (value[0] == 'unary-prefix' && value[2][0] == 'num')); // must be valid coercion no-op ++ if (!(value[0] == 'num' || (value[0] == 'unary-prefix' && value[2][0] == 'num'))) break outer; // must be valid coercion no-op + data.vars[name] = detectAsmCoercion(value); + v.length = 1; // make an un-assigning var + } else { +@@ -1331,6 +1331,7 @@ function normalizeAsm(func) { + i++; + } + // finally, look for other var definitions and collect them ++ var extra = []; + while (i < stats.length) { + traverse(stats[i], function(node, type) { + if (type == 'var') { +@@ -1340,6 +1341,7 @@ function normalizeAsm(func) { + var value = v[1]; + if (!(name in data.vars)) { + data.vars[name] = detectAsmCoercion(value); ++ extra.push(['var', [[name]]]); // add a 'var' for normal JS + } + } + unVarify(node[1], node); +@@ -1353,6 +1355,7 @@ function normalizeAsm(func) { + }); + i++; + } ++ if (extra.length > 0) stats.splice.apply(stats, [0, 0].concat(extra)); + //printErr('normalized \n\n' + astToSrc(func) + '\n\nwith: ' + JSON.stringify(data)); + return data; + } +diff --git a/tools/test-js-optimizer-asm-regs-output.js b/tools/test-js-optimizer-asm-regs-output.js +index 99bccd2..f84b8d5 100644 +--- a/tools/test-js-optimizer-asm-regs-output.js ++++ b/tools/test-js-optimizer-asm-regs-output.js +@@ -9,6 +9,18 @@ function asm(d1, i2) { + d4 = d1 * 5; + return d4; + } ++function asm2(d1, i2) { ++ d1 = +d1; ++ i2 = i2 | 0; ++ var i3 = 0, d4 = +0; ++ i3 = i2; ++ i2 = d1 + i3 | 0; ++ d1 = d(Math_max(10, Math_min(5, f()))); ++ i3 = i2 + 2 | 0; ++ print(i3); ++ d4 = d1 * 5; ++ return d4; ++} + function _doit(i1, i2, i3) { + i1 = i1 | 0; + i2 = i2 | 0; +diff --git a/tools/test-js-optimizer-asm-regs.js b/tools/test-js-optimizer-asm-regs.js +index 0afced2..fbaa7c4 100644 +--- a/tools/test-js-optimizer-asm-regs.js ++++ b/tools/test-js-optimizer-asm-regs.js +@@ -10,6 +10,19 @@ function asm(x, y) { + double2 = double1*5; + return double2; + } ++function asm2(x, y) { ++ x = +x; ++ y = y | 0; ++ var int1 = 0, int2 = 0; // do not mix the types! ++ var double1 = +0, double2 = +0; ++ var tempy = y; ++ int1 = (x+tempy)|0; ++ double1 = d(Math.max(10, Math_min(5, f()))); ++ int2 = (int1+2)|0; ++ print(int2); ++ double2 = double1*5; ++ return double2; ++} + function _doit($x, $y$0, $y$1) { + $x = $x | 0; + $y$0 = $y$0 | 0; +@@ -41,5 +54,5 @@ function retf() { + } + // missing final return, need it as a float + } +-// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "_doit", "rett", "ret2t", "retf"] ++// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "asm2", "_doit", "rett", "ret2t", "retf"] + diff --git a/src/intertyper.js b/src/intertyper.js index c1a98354..2103ecfa 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -677,7 +677,7 @@ function intertyper(data, sidePass, baseLineNums) { item.type = item.tokens[1].text; Types.needAnalysis[item.type] = 0; while (['@', '%'].indexOf(item.tokens[2].text[0]) == -1 && !(item.tokens[2].text in PARSABLE_LLVM_FUNCTIONS) && - item.tokens[2].text != 'null' && item.tokens[2].text != 'asm') { + item.tokens[2].text != 'null' && item.tokens[2].text != 'asm' && item.tokens[2].text != 'undef') { assert(item.tokens[2].text != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); item.tokens.splice(2, 1); } @@ -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 761a5fec..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_) { @@ -478,8 +479,7 @@ function JSify(data, functionsOnly, givenFunctions) { ident = '_' + ident; } var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); - // redirected idents just need a var, but no value assigned to them - it would be unused - var contentText = isFunction ? snippet : ('var ' + ident + (redirectedIdent ? '' : '=' + snippet) + ';'); + var contentText = isFunction ? snippet : ('var ' + ident + '=' + snippet + ';'); if (ASM_JS) { var sig = LibraryManager.library[ident.substr(1) + '__sig']; if (isFunction && sig && LibraryManager.library[ident.substr(1) + '__asm']) { @@ -506,9 +506,9 @@ 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) { + if (WARN_ON_UNDEFINED_SYMBOLS || ASM_JS) { // always warn on undefs in asm, since it breaks validation warn('Unresolved symbol: ' + item.ident); } } @@ -631,15 +631,6 @@ function JSify(data, functionsOnly, givenFunctions) { } } - if (PROFILE) { - func.JS += ' if (PROFILING) { ' - + 'var __parentProfilingNode__ = PROFILING_NODE; PROFILING_NODE = PROFILING_NODE.children["' + func.ident + '"]; ' - + 'if (!PROFILING_NODE) __parentProfilingNode__.children["' + func.ident + '"] = PROFILING_NODE = { time: 0, children: {}, calls: 0 };' - + 'PROFILING_NODE.calls++; ' - + 'var __profilingStartTime__ = Date.now() ' - + '}\n'; - } - if (true) { // TODO: optimize away when not needed if (CLOSURE_ANNOTATIONS) func.JS += '/** @type {number} */'; func.JS += ' var label = 0;\n'; @@ -923,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; @@ -1145,12 +1140,6 @@ function JSify(data, functionsOnly, givenFunctions) { }); makeFuncLineActor('return', function(item) { var ret = RuntimeGenerator.stackExit(item.funcData.initialStack, item.funcData.otherStackAllocations) + ';\n'; - if (PROFILE) { - ret += 'if (PROFILING) { ' - + 'PROFILING_NODE.time += Date.now() - __profilingStartTime__; ' - + 'PROFILING_NODE = __parentProfilingNode__ ' - + '}\n'; - } if (LABEL_DEBUG && functionNameFilterTest(item.funcData.ident)) { ret += "Module.print(INDENT + 'Exiting: " + item.funcData.ident + "');\n" + "INDENT = INDENT.substr(0, INDENT.length-2);\n"; @@ -1215,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; } @@ -1237,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); @@ -1260,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) + '], '; } @@ -1300,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) { @@ -1417,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 + ']'; } @@ -1527,7 +1532,7 @@ function JSify(data, functionsOnly, givenFunctions) { print('// ASM_LIBRARY FUNCTIONS'); function fix(f) { // fix indenting to not confuse js optimizer f = f.substr(f.indexOf('f')); // remove initial spaces before 'function' - f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last } + f = f.substr(0, f.lastIndexOf('\n')+1); // remove spaces and last } XXX assumes function has multiple lines return f + '}'; // add unindented } to match function } print(asmLibraryFunctions.map(fix).join('\n')); @@ -1547,6 +1552,10 @@ function JSify(data, functionsOnly, givenFunctions) { // This is the main 'post' pass. Print out the generated code that we have here, together with the // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). + if (CORRUPTION_CHECK) { + assert(!ASM_JS); // cannot monkeypatch asm! + print(processMacros(read('corruptionCheck.js'))); + } if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { print(read('long.js')); } else { @@ -1579,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 1e026937..d787e30c 100644 --- a/src/library.js +++ b/src/library.js @@ -624,7 +624,12 @@ LibraryManager.library = { // dirent.h // ========================================================================== - __dirent_struct_layout: Runtime.generateStructInfo(['d_ino', 'd_name', 'd_off', 'd_reclen', 'd_type'], '%struct.dirent'), + __dirent_struct_layout: Runtime.generateStructInfo([ + ['i32', 'd_ino'], + ['b1024', 'd_name'], + ['i32', 'd_off'], + ['i32', 'd_reclen'], + ['i32', 'd_type']]), opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'], opendir: function(dirname) { // DIR *opendir(const char *dirname); @@ -786,7 +791,9 @@ LibraryManager.library = { // utime.h // ========================================================================== - __utimbuf_struct_layout: Runtime.generateStructInfo(['actime', 'modtime'], '%struct.utimbuf'), + __utimbuf_struct_layout: Runtime.generateStructInfo([ + ['i32', 'actime'], + ['i32', 'modtime']]), utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'], utime: function(path, times) { // int utime(const char *path, const struct utimbuf *times); @@ -877,23 +884,23 @@ LibraryManager.library = { // ========================================================================== __stat_struct_layout: Runtime.generateStructInfo([ - 'st_dev', - 'st_ino', - 'st_mode', - 'st_nlink', - 'st_uid', - 'st_gid', - 'st_rdev', - 'st_size', - 'st_atime', - 'st_spare1', - 'st_mtime', - 'st_spare2', - 'st_ctime', - 'st_spare3', - 'st_blksize', - 'st_blocks', - 'st_spare4'], '%struct.stat'), + ['i32', 'st_dev'], + ['i32', 'st_ino'], + ['i32', 'st_mode'], + ['i32', 'st_nlink'], + ['i32', 'st_uid'], + ['i32', 'st_gid'], + ['i32', 'st_rdev'], + ['i32', 'st_size'], + ['i32', 'st_atime'], + ['i32', 'st_spare1'], + ['i32', 'st_mtime'], + ['i32', 'st_spare2'], + ['i32', 'st_ctime'], + ['i32', 'st_spare3'], + ['i32', 'st_blksize'], + ['i32', 'st_blocks'], + ['i32', 'st_spare4']]), stat__deps: ['$FS', '__stat_struct_layout'], stat: function(path, buf, dontResolveLastLink) { // http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html @@ -1065,17 +1072,17 @@ LibraryManager.library = { // ========================================================================== __statvfs_struct_layout: Runtime.generateStructInfo([ - 'f_bsize', - 'f_frsize', - 'f_blocks', - 'f_bfree', - 'f_bavail', - 'f_files', - 'f_ffree', - 'f_favail', - 'f_fsid', - 'f_flag', - 'f_namemax'], '%struct.statvfs'), + ['i32', 'f_bsize'], + ['i32', 'f_frsize'], + ['i32', 'f_blocks'], + ['i32', 'f_bfree'], + ['i32', 'f_bavail'], + ['i32', 'f_files'], + ['i32', 'f_ffree'], + ['i32', 'f_favail'], + ['i32', 'f_fsid'], + ['i32', 'f_flag'], + ['i32', 'f_namemax']]), statvfs__deps: ['$FS', '__statvfs_struct_layout'], statvfs: function(path, buf) { // http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html @@ -1110,12 +1117,12 @@ LibraryManager.library = { // ========================================================================== __flock_struct_layout: Runtime.generateStructInfo([ - 'l_type', - 'l_whence', - 'l_start', - 'l_len', - 'l_pid', - 'l_xxx'], '%struct.flock'), + ['i16', 'l_type'], + ['i16', 'l_whence'], + ['i32', 'l_start'], + ['i32', 'l_len'], + ['i16', 'l_pid'], + ['i16', 'l_xxx']]), open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'], open: function(path, oflag, varargs) { // int open(const char *path, int oflag, ...); @@ -1336,7 +1343,10 @@ LibraryManager.l |