diff options
Diffstat (limited to 'src/jsifier.js')
-rw-r--r-- | src/jsifier.js | 103 |
1 files changed, 76 insertions, 27 deletions
diff --git a/src/jsifier.js b/src/jsifier.js index 32c224b7..8ab96a25 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -486,11 +486,18 @@ function JSify(data, functionsOnly, givenFunctions) { item.JS = ''; } else { // If this is not linkable, anything not in the library is definitely missing + var cancel = false; if (!LINKABLE && !LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) { + if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + shortident); if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) printErr('warning: unresolved symbol: ' + shortident); - LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); + if (ASM_JS || item.ident in DEAD_FUNCTIONS) { + // emit a stub that will fail during runtime. this allows asm validation to succeed. + LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); + } else { + cancel = true; // emit nothing, not even var X = undefined; + } } - item.JS = addFromLibrary(shortident); + item.JS = cancel ? ';' : addFromLibrary(shortident); } return ret; } @@ -1174,6 +1181,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (disabled) { ret = call_ + ';'; } else if (ASM_JS) { + call_ = call_.replace('; return', ''); // we auto-add returns when aborting, but do not need them here ret = '(__THREW__ = 0,' + call_ + ');'; } else { ret = '(function() { try { __THREW__ = 0; return ' @@ -1224,7 +1232,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (DISABLE_EXCEPTION_CATCHING && USE_TYPED_ARRAYS == 2) { ret = makeVarDef(item.assignTo) + '$0 = 0; ' + item.assignTo + '$1 = 0;'; item.assignTo = null; - if (ASSERTIONS) warnOnce('landingpad, but exceptions are disabled!'); + if (VERBOSE) warnOnce('landingpad, but exceptions are disabled!'); return ret; } var catchTypeArray = item.catchables.map(finalizeLLVMParameter).map(function(element) { return asmCoercion(element, 'i32') }).join(','); @@ -1294,6 +1302,14 @@ function JSify(data, functionsOnly, givenFunctions) { return RuntimeGenerator.stackAlloc(getFastValue(calcAllocatedSize(item.allocatedType), '*', item.allocatedNum)); } }); + makeFuncLineActor('va_arg', function(item) { + assert(TARGET_LE32); + var ident = item.value.ident; + var move = Runtime.STACK_ALIGN; + return '(tempInt=' + makeGetValue(ident, 4, '*') + ',' + + makeSetValue(ident, 4, 'tempInt + ' + move, '*') + ',' + + makeGetValue(makeGetValue(ident, 0, '*'), 'tempInt', item.type) + ')'; + }); makeFuncLineActor('mathop', processMathop); @@ -1317,16 +1333,21 @@ function JSify(data, functionsOnly, givenFunctions) { ident = Variables.resolveAliasToIdent(ident); var shortident = ident.slice(1); var simpleIdent = shortident; - var callIdent = LibraryManager.getRootIdent(simpleIdent); - if (callIdent) { - simpleIdent = callIdent; // ident may not be in library, if all there is is ident__inline, but in this case it is - if (callIdent.indexOf('.') < 0) { - callIdent = '_' + callIdent; // Not Math.*, so add the normal prefix - } + if (isLocalVar(ident)) { + var callIdent = ident; } else { - callIdent = ident; + // Not a local var, check if in library + var callIdent = LibraryManager.getRootIdent(simpleIdent); + if (callIdent) { + simpleIdent = callIdent; // ident may not be in library, if all there is is ident__inline, but in this case it is + if (callIdent.indexOf('.') < 0) { + callIdent = '_' + callIdent; // Not Math.*, so add the normal prefix + } + } else { + callIdent = ident; + } + if (callIdent == '0') return 'abort(-2)'; } - if (callIdent == '0') return 'abort(-2)'; var args = []; var argsTypes = []; @@ -1357,6 +1378,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { size = Runtime.getNativeFieldSize(param.type); } + size = Runtime.alignMemory(size, Runtime.STACK_ALIGN); varargs.push(val); varargs = varargs.concat(zeros(size-1)); // TODO: replace concats like this with push @@ -1389,16 +1411,16 @@ function JSify(data, functionsOnly, givenFunctions) { varargs.map(function(arg, i) { var type = varargsTypes[i]; if (type == 0) return null; + arg = asmEnsureFloat(arg, type); var ret; + assert(offset % Runtime.STACK_ALIGN == 0); // varargs must be aligned if (!varargsByVals[i]) { - ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, QUANTUM_SIZE, null, ','); - offset += Runtime.getNativeFieldSize(type); + ret = makeSetValue(getFastValue('tempInt', '+', offset), 0, arg, type, null, null, Runtime.STACK_ALIGN, null, ','); + offset += Runtime.alignMemory(Runtime.getNativeFieldSize(type), Runtime.STACK_ALIGN); } else { - assert(offset % 4 == 0); // varargs must be aligned var size = calcAllocatedSize(removeAllPointing(type)); - assert(size % 4 == 0); // varargs must stay aligned ret = makeCopyValues(getFastValue('tempInt', '+', offset), arg, size, null, null, varargsByVals[i], ','); - offset += size; + offset += Runtime.forceAlign(size, Runtime.STACK_ALIGN); } return ret; }).filter(function(arg) { @@ -1442,6 +1464,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (!byPointerForced && !funcData.setjmpTable) { // normal asm function pointer call callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py + Functions.neededTables[sig] = 1; } else { // This is a call through an invoke_*, either a forced one, or a setjmp-required one // note: no need to update argsTypes at this point @@ -1467,7 +1490,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (ASM_JS && funcData.setjmpTable) { // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it. // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way - ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; } return ret; @@ -1525,13 +1548,9 @@ function JSify(data, functionsOnly, givenFunctions) { if (!mainPass) { if (phase == 'pre' && !Variables.generatedGlobalBase) { Variables.generatedGlobalBase = true; - if (Variables.nextIndexedOffset > 0) { - // Variables have been calculated, get to base stuff before we print them - // GLOBAL_BASE is statically known to be equal to STACK_MAX and to TOTAL_STACK, assert on this - print('assert(STATICTOP == STACK_MAX); assert(STACK_MAX == TOTAL_STACK);\n'); - print('STATICTOP += ' + Variables.nextIndexedOffset + ';\n'); - print('assert(STATICTOP < TOTAL_MEMORY);\n'); - } + // Globals are done, here is the rest of static memory + print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n'); + print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); } var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); print(generated.map(function(item) { return item.JS }).join('\n')); @@ -1552,13 +1571,13 @@ function JSify(data, functionsOnly, givenFunctions) { // possibly function table {{{ FT_* }}} etc. if (value.indexOf('{{ ') < 0) return true; } - writeInt8s(memoryInitialization, target - TOTAL_STACK, value, type); + writeInt8s(memoryInitialization, target - Runtime.GLOBAL_BASE, value, type); return false; } return true; }); // write out the singleton big memory initialization value - print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'TOTAL_STACK', true)); // we assert on TOTAL_STACK == GLOBAL_BASE + print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE', true)); } else { print('/* no memory initializer */'); // test purposes } @@ -1568,6 +1587,27 @@ function JSify(data, functionsOnly, givenFunctions) { print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); print('}\n'); print('if (!awaitingMemoryInitializer) runPostSets();\n'); // if we load the memory initializer, this is done later + + if (USE_TYPED_ARRAYS == 2) { + print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n'); + print('assert(tempDoublePtr % 8 == 0);\n'); + print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print('}\n'); + print('function copyTempDouble(ptr) {\n'); + print(' HEAP8[tempDoublePtr] = HEAP8[ptr];\n'); + print(' HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n'); + print(' HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n'); + print(' HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n'); + print(' HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n'); + print(' HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n'); + print(' HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n'); + print(' HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n'); + print('}\n'); + } } return; @@ -1584,10 +1624,11 @@ function JSify(data, functionsOnly, givenFunctions) { sortGlobals(globalsData.globalVariables).forEach(function(g) { var ident = g.ident; if (!isIndexableGlobal(ident)) return; + assert(Variables.nextIndexedOffset % Runtime.STACK_ALIGN == 0); Variables.indexedGlobals[ident] = Variables.nextIndexedOffset; Variables.nextIndexedOffset += Runtime.alignMemory(calcAllocatedSize(Variables.globals[ident].type)); if (ident.substr(0, 5) == '__ZTV') { // leave room for null-terminating the vtable - Variables.nextIndexedOffset += Runtime.getNativeTypeSize('i32'); + Variables.nextIndexedOffset += Runtime.alignMemory(QUANTUM_SIZE); } }); } @@ -1600,6 +1641,12 @@ function JSify(data, functionsOnly, givenFunctions) { legalizedI64s = legalizedI64sDefault; + print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n'); + print('staticSealed = true; // seal the static portion of memory\n'); + print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n'); + print('DYNAMIC_BASE = DYNAMICTOP = Runtime.alignMemory(STACK_MAX);\n'); + print('assert(DYNAMIC_BASE < TOTAL_MEMORY); // Stack must fit in TOTAL_MEMORY; allocations from here on may enlarge TOTAL_MEMORY\n'); + if (asmLibraryFunctions.length > 0) { print('// ASM_LIBRARY FUNCTIONS'); function fix(f) { // fix indenting to not confuse js optimizer @@ -1609,6 +1656,7 @@ function JSify(data, functionsOnly, givenFunctions) { } print(asmLibraryFunctions.map(fix).join('\n')); } + } else { if (singlePhase) { assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss])); @@ -1642,6 +1690,7 @@ function JSify(data, functionsOnly, givenFunctions) { assert(typeof dep == 'function'); var text = dep(); assert(text.indexOf('\n') < 0); + text = text.replace('ALLOC_STATIC', 'ALLOC_DYNAMIC'); print('/* PRE_ASM */ ' + text + '\n'); }); } |