aboutsummaryrefslogtreecommitdiff
path: root/src/jsifier.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsifier.js')
-rw-r--r--src/jsifier.js103
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');
});
}