aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js2
-rw-r--r--src/intertyper.js6
-rw-r--r--src/jsifier.js70
-rw-r--r--src/library.js188
-rw-r--r--src/library_gc.js13
-rw-r--r--src/library_gl.js3
-rw-r--r--src/modules.js33
-rw-r--r--src/parseTools.js27
-rw-r--r--src/preamble.js29
-rw-r--r--src/settings.js5
-rw-r--r--src/utility.js2
11 files changed, 273 insertions, 105 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index c09739e9..014579f4 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -690,6 +690,8 @@ function analyzer(data, sidePass) {
var subType = check[2];
addTypeInternal(subType, data); // needed for anonymous structure definitions (see below)
+ // Huge structural types are represented very inefficiently, both here and in generated JS. Best to avoid them - for example static char x[10*1024*1024]; is bad, while static char *x = malloc(10*1024*1024) is fine.
+ if (num >= 10*1024*1024) warnOnce('warning: very large fixed-size structural type: ' + type + ' - can you reduce it? (compilation may be slow)');
Types.types[nonPointing] = {
name_: nonPointing,
fields: range(num).map(function() { return subType }),
diff --git a/src/intertyper.js b/src/intertyper.js
index fbad353a..8e7bb418 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -165,7 +165,7 @@ function intertyper(data, sidePass, baseLineNums) {
function makeToken(text) {
if (text.length == 0) return;
// merge certain tokens
- if (lastToken && ( (lastToken.text == '%' && text[0] == '"') || /^\**$/.exec(text) ) ) {
+ if (lastToken && ( (lastToken.text == '%' && text[0] == '"') || /^\**$/.test(text) ) ) {
lastToken.text += text;
return;
}
@@ -182,7 +182,7 @@ function intertyper(data, sidePass, baseLineNums) {
// merge certain tokens
if (lastToken && isType(lastToken.text) && isFunctionDef(token)) {
lastToken.text += ' ' + text;
- } else if (lastToken && /^}\**$/.exec(text)) { // }, }*, etc.
+ } else if (lastToken && text[0] == '}') { // }, }*, etc.
var openBrace = tokens.length-1;
while (tokens[openBrace].text.substr(-1) != '{') openBrace --;
token = combineTokens(tokens.slice(openBrace+1));
@@ -674,7 +674,7 @@ function intertyper(data, sidePass, baseLineNums) {
// Inline assembly is just JavaScript that we paste into the code
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
- item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2);
+ item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
return { forward: null, ret: [item], item: item };
}
if (item.ident.substr(-2) == '()') {
diff --git a/src/jsifier.js b/src/jsifier.js
index fae92f70..595e057c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -65,24 +65,27 @@ function JSify(data, functionsOnly, givenFunctions) {
// Add additional necessary items for the main pass. We can now do this since types are parsed (types can be used through
// generateStructInfo in library.js)
LibraryManager.load();
- var libFuncsToInclude;
- if (INCLUDE_FULL_LIBRARY) {
- assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
- libFuncsToInclude = [];
- for (var key in LibraryManager.library) {
- if (!key.match(/__(deps|postset|inline)$/)) {
- libFuncsToInclude.push(key);
+
+ if (phase == 'pre') {
+ var libFuncsToInclude;
+ if (INCLUDE_FULL_LIBRARY) {
+ assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
+ libFuncsToInclude = [];
+ for (var key in LibraryManager.library) {
+ if (!key.match(/__(deps|postset|inline)$/)) {
+ libFuncsToInclude.push(key);
+ }
}
+ } else {
+ libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE;
}
- } else {
- libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE;
- }
- libFuncsToInclude.forEach(function(ident) {
- data.functionStubs.push({
- intertype: 'functionStub',
- ident: '_' + ident
+ libFuncsToInclude.forEach(function(ident) {
+ data.functionStubs.push({
+ intertype: 'functionStub',
+ ident: '_' + ident
+ });
});
- });
+ }
}
// Functions
@@ -329,7 +332,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (item.ident.substr(0, 5) == '__ZTV') {
js += '\n' + makePointer('[0]', null, BUILD_AS_SHARED_LIB ? 'ALLOC_NORMAL' : 'ALLOC_STATIC', ['void*']) + ';';
}
- if (item.ident in EXPORTED_GLOBALS) {
+ if (EXPORT_ALL || (item.ident in EXPORTED_GLOBALS)) {
js += '\nModule["' + item.ident + '"] = ' + item.ident + ';';
}
if (BUILD_AS_SHARED_LIB == 2 && !item.private_) {
@@ -439,7 +442,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}
var text = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : '');
text += isFunction ? snippet : 'var ' + ident + '=' + snippet + ';';
- if (ident in EXPORTED_FUNCTIONS) {
+ if (EXPORT_ALL || (ident in EXPORTED_FUNCTIONS)) {
text += '\nModule["' + ident + '"] = ' + ident + ';';
}
return text;
@@ -616,6 +619,7 @@ function JSify(data, functionsOnly, givenFunctions) {
} // otherwise, should have been set before!
if (func.setjmpTable) {
var setjmpTable = {};
+ ret += indent + 'var setjmped = false;'; // set to true if we setjmp in this invocation
ret += indent + 'var setjmpTable = {';
func.setjmpTable.forEach(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into
ret += '"' + getLabelId(triple[0]) + '": ' + 'function(value) { label = ' + getLabelId(triple[1]) + '; ' + triple[2] + ' = value },';
@@ -634,7 +638,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}).join('\n');
ret += '\n' + indent + ' default: assert(0, "bad label: " + label);\n' + indent + '}';
if (func.setjmpTable) {
- ret += ' } catch(e) { if (!e.longjmp) throw(e); setjmpTable[e.label](e.value) }';
+ ret += ' } catch(e) { if (!setjmped) throw(e); if (!e.longjmp) throw(e); setjmpTable[e.label](e.value) }';
}
} else {
ret += (SHOW_LABELS ? indent + '/* ' + block.entries[0] + ' */' : '') + '\n' + getLabelLines(block.labels[0], indent);
@@ -699,7 +703,7 @@ function JSify(data, functionsOnly, givenFunctions) {
func.JS += '\n//FUNCTION_END_MARKER_OF_SOURCE_FILE_' + associatedSourceFile + '\n';
}
- if (func.ident in EXPORTED_FUNCTIONS) {
+ if (EXPORT_ALL || (func.ident in EXPORTED_FUNCTIONS)) {
func.JS += 'Module["' + func.ident + '"] = ' + func.ident + ';';
}
@@ -1066,12 +1070,12 @@ function JSify(data, functionsOnly, givenFunctions) {
var param1 = finalizeLLVMParameter(item.params[0]);
var param2 = finalizeLLVMParameter(item.params[1]);
switch (item.op) {
- case 'add': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue+' + param2, type) + ',tempValue)';
- case 'sub': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, 'tempValue-' + param2, type) + ',tempValue)';
- case 'xchg': return '(tempValue=' + makeGetValue(param1, 0, type) + ',' + makeSetValue(param1, 0, param2, type) + ',tempValue)';
+ 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 '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) + ')),tempValue)';
+ return '(tempValue=' + makeGetValue(param1, 0, type) + ',(' + makeGetValue(param1, 0, type) + '==' + param2 + ' && (' + makeSetValue(param1, 0, param3, type, null, null, null, null, ',') + ')),tempValue)';
}
default: throw 'unhandled atomic op: ' + item.op;
}
@@ -1279,6 +1283,19 @@ function JSify(data, functionsOnly, givenFunctions) {
return;
}
+ // Print out global variables and postsets TODO: batching
+ if (phase == 'pre') {
+ legalizedI64s = false;
+ JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions);
+ data.unparsedGlobalss = null;
+
+ var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet);
+ generated.forEach(function(item) { print(indentify(item.JS || '', 2)); });
+ } else {
+ assert(data.unparsedGlobalss[0].lines.length == 0, dump([phase, data.unparsedGlobalss]));
+ assert(itemsDict.functionStub.length == 0, dump([phase, itemsDict.functionStub]));
+ }
+
if (phase == 'pre' || phase == 'funcs') {
// serialize out the data that later passes need
PassManager.serialize(); // XXX for funcs pass, do not serialize it all. I think we just need which were indexized.
@@ -1299,8 +1316,6 @@ function JSify(data, functionsOnly, givenFunctions) {
print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0'));
print('}');
}
- var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet);
- generated.forEach(function(item) { print(indentify(item.JS || '', 2)); });
if (RUNTIME_TYPE_INFO) {
Types.cleanForRuntime();
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
@@ -1310,11 +1325,6 @@ function JSify(data, functionsOnly, givenFunctions) {
var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}');
print(postParts[0]);
- // Print out global variables and postsets TODO: batching
- legalizedI64s = false;
- JSify(analyzer(intertyper(data.unparsedGlobalss[0].lines, true), true), true, Functions);
- data.unparsedGlobalss = null;
-
print(Functions.generateIndexing()); // done last, as it may rely on aliases set in postsets
// Load runtime-linked libraries
diff --git a/src/library.js b/src/library.js
index fd5e0fae..06661d59 100644
--- a/src/library.js
+++ b/src/library.js
@@ -2457,20 +2457,23 @@ LibraryManager.library = {
var argIndex = 0;
var next;
- next = 1;
mainLoop:
- for (var formatIndex = 0; formatIndex < format.length; formatIndex++) {
+ for (var formatIndex = 0; formatIndex < format.length;) {
+ if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getNativeFieldSize('void*');
+ {{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
+ formatIndex += 2;
+ continue;
+ }
+
// remove whitespace
while (1) {
next = get();
if (next == 0) return fields;
if (!(next in __scanString.whiteSpace)) break;
- }
- unget(next);
-
- if (next <= 0) return fields;
- var next = get();
- if (next <= 0) return fields; // End of input.
+ }
+ unget();
if (format[formatIndex] === '%') {
formatIndex++;
@@ -2504,6 +2507,7 @@ LibraryManager.library = {
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
if (type == 'f') {
var last = 0;
+ next = get();
while (next > 0) {
buffer.push(String.fromCharCode(next));
if (__isFloat(buffer.join(''))) {
@@ -2511,12 +2515,12 @@ LibraryManager.library = {
}
next = get();
}
- unget(next);
- while (buffer.length > last) {
- unget(buffer.pop().charCodeAt(0));
+ for (var i = 0; i < buffer.length - last + 1; i++) {
+ unget();
}
+ buffer.length = last;
+ } else {
next = get();
- } else if (type != 'n') {
var first = true;
while ((curr < max_ || isNaN(max_)) && next > 0) {
if (!(next in __scanString.whiteSpace) && // stop on whitespace
@@ -2530,13 +2534,14 @@ LibraryManager.library = {
buffer.push(String.fromCharCode(next));
next = get();
curr++;
+ first = false;
} else {
break;
}
- first = false;
}
+ unget();
}
- if (buffer.length === 0 && type != 'n') return 0; // Failure.
+ if (buffer.length === 0) return 0; // Failure.
var text = buffer.join('');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getNativeFieldSize('void*');
@@ -2566,31 +2571,26 @@ LibraryManager.library = {
{{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
}
break;
- case 'n':
- {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}}
- break;
}
- if (type != 'n') fields++;
- if (next <= 0) break mainLoop; // End of input.
+ fields++;
} else if (format[formatIndex] in __scanString.whiteSpace) {
+ next = get();
while (next in __scanString.whiteSpace) {
- next = get();
if (next <= 0) break mainLoop; // End of input.
+ next = get();
}
unget(next);
+ formatIndex++;
} else {
// Not a specifier.
+ next = get();
if (format[formatIndex].charCodeAt(0) !== next) {
unget(next);
break mainLoop;
}
+ formatIndex++;
}
}
- // 'n' is special in that it needs no input. so it can be at the end, even with nothing left to read
- if (format[formatIndex-1] == '%' && format[formatIndex] == 'n') {
- var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
- {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}}
- }
return fields;
},
// Performs prtinf-style formatting.
@@ -2741,7 +2741,7 @@ LibraryManager.library = {
var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0);
argSize = argSize || 4;
var currArg = getNextArg('i' + (argSize * 8));
-#if PRECISE_I64_MATH == 1
+#if PRECISE_I64_MATH
var origArg = currArg;
#endif
var argText;
@@ -2760,12 +2760,12 @@ LibraryManager.library = {
var currAbsArg = Math.abs(currArg);
var prefix = '';
if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) {
-#if PRECISE_I64_MATH == 1
- if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1]); else
+#if PRECISE_I64_MATH
+ if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
#endif
argText = reSign(currArg, 8 * argSize, 1).toString(10);
} else if (next == 'u'.charCodeAt(0)) {
-#if PRECISE_I64_MATH == 1
+#if PRECISE_I64_MATH
if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
#endif
argText = unSign(currArg, 8 * argSize, 1).toString(10);
@@ -2774,6 +2774,9 @@ LibraryManager.library = {
argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
} else if (next == 'x'.charCodeAt(0) || next == 'X'.charCodeAt(0)) {
prefix = flagAlternative ? '0x' : '';
+#if PRECISE_I64_MATH
+ if (argSize == 8 && i64Math) argText = (origArg[1]>>>0).toString(16) + (origArg[0]>>>0).toString(16); else
+#endif
if (currArg < 0) {
// Represent negative numbers in hex as 2's complement.
currArg = -currArg;
@@ -3452,8 +3455,9 @@ LibraryManager.library = {
// int fscanf(FILE *restrict stream, const char *restrict format, ... );
// http://pubs.opengroup.org/onlinepubs/000095399/functions/scanf.html
if (FS.streams[stream]) {
- var get = function() { return _fgetc(stream); };
- var unget = function(c) { return _ungetc(c, stream); };
+ var stack = [];
+ var get = function() { var ret = _fgetc(stream); stack.push(ret); return ret };
+ var unget = function(c) { return _ungetc(stack.pop(), stream) };
return __scanString(format, get, unget, varargs);
} else {
return -1;
@@ -3735,6 +3739,7 @@ LibraryManager.library = {
strtod_l: 'strtod', // no locale support yet
strtold: 'strtod', // XXX add real support for long double
strtold_l: 'strtold', // no locale support yet
+ strtof: 'strtod', // use stdtod to handle strtof
_parseInt__deps: ['isspace', '__setErrNo', '$ERRNO_CODES'],
_parseInt: function(str, endptr, base, min, max, bits, unsign) {
@@ -4035,6 +4040,10 @@ LibraryManager.library = {
return Math.floor(Math.random()*0x80000000);
},
+ drand48: function() {
+ return Math.random();
+ },
+
realpath__deps: ['$FS', '__setErrNo'],
realpath: function(file_name, resolved_name) {
// char *realpath(const char *restrict file_name, char *restrict resolved_name);
@@ -4742,6 +4751,10 @@ LibraryManager.library = {
return 32;
},
+ llvm_trap: function() {
+ throw 'trap! ' + new Error().stack;
+ },
+
__assert_fail: function(condition, file, line) {
ABORT = true;
throw 'Assertion failed: ' + Pointer_stringify(condition);//JSON.stringify(arguments)//condition;
@@ -5105,6 +5118,34 @@ LibraryManager.library = {
llvm_objectsize_i32: function() { return -1 }, // TODO: support this
// ==========================================================================
+ // llvm-mono integration
+ // ==========================================================================
+
+ llvm_mono_load_i8_p0i8: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i8') }}};
+ },
+
+ llvm_mono_store_i8_p0i8: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i8') }}};
+ },
+
+ llvm_mono_load_i16_p0i16: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i16') }}};
+ },
+
+ llvm_mono_store_i16_p0i16: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i16') }}};
+ },
+
+ llvm_mono_load_i32_p0i32: function(ptr) {
+ return {{{ makeGetValue('ptr', 0, 'i32') }}};
+ },
+
+ llvm_mono_store_i32_p0i32: function(value, ptr) {
+ {{{ makeSetValue('ptr', 0, 'value', 'i32') }}};
+ },
+
+ // ==========================================================================
// math.h
// ==========================================================================
@@ -5124,6 +5165,64 @@ LibraryManager.library = {
atan2f: 'Math.atan2',
exp: 'Math.exp',
expf: 'Math.exp',
+
+ // The erf and erfc functions are inspired from
+ // http://www.digitalmars.com/archives/cplusplus/3634.html
+ // and mruby source code at
+ // https://github.com/mruby/mruby/blob/master/src/math.c
+ erfc: function (x) {
+ var MATH_TOLERANCE = 1E-12;
+ var ONE_SQRTPI = 0.564189583547756287;
+ var a = 1;
+ var b = x;
+ var c = x;
+ var d = x * x + 0.5;
+ var n = 1.0;
+ var q2 = b / d;
+ var q1, t;
+
+ if (Math.abs(x) < 2.2) {
+ return 1.0 - _erf(x);
+ }
+ if (x < 0) {
+ return 2.0 - _erfc(-x);
+ }
+ do {
+ t = a * n + b * x;
+ a = b;
+ b = t;
+ t = c * n + d * x;
+ c = d;
+ d = t;
+ n += 0.5;
+ q1 = q2;
+ q2 = b / d;
+ } while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
+ return (ONE_SQRTPI * Math.exp(- x * x) * q2);
+ },
+ erfcf: 'erfcf',
+ erf: function (x) {
+ var MATH_TOLERANCE = 1E-12;
+ var TWO_SQRTPI = 1.128379167095512574;
+ var sum = x;
+ var term = x;
+ var xsqr = x*x;
+ var j = 1;
+
+ if (Math.abs(x) > 2.2) {
+ return 1.0 - _erfc(x);
+ }
+ do {
+ term *= xsqr / j;
+ sum -= term / (2 * j + 1);
+ ++j;
+ term *= xsqr / j;
+ sum += term / (2 * j + 1);
+ ++j;
+ } while (Math.abs(term / sum) > MATH_TOLERANCE);
+ return (TWO_SQRTPI * sum);
+ },
+ erff: 'erf',
log: 'Math.log',
logf: 'Math.log',
sqrt: 'Math.sqrt',
@@ -5266,7 +5365,7 @@ LibraryManager.library = {
},
fmaxf: 'fmax',
fmin: function(x, y) {
- return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
+ return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
},
fminf: 'fmin',
fma: function(x, y, z) {
@@ -5841,7 +5940,7 @@ LibraryManager.library = {
setjmp__inline: function(env) {
// Save the label
- return '(' + makeSetValue(env, '0', 'label', 'i32') + ', 0)';
+ return '(setjmped = true, ' + makeSetValue(env, '0', 'label', 'i32') + ', 0)';
},
longjmp: function(env, value) {
@@ -6404,6 +6503,17 @@ LibraryManager.library = {
_pthread_key_create.keys[key] = value;
},
+ pthread_cleanup_push: function(routine, arg) {
+ __ATEXIT__.push({ func: function() { FUNCTION_TABLE[routine](arg) } })
+ _pthread_cleanup_push.level = __ATEXIT__.length;
+ },
+
+ pthread_cleanup_pop: function() {
+ assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
+ __ATEXIT__.pop();
+ _pthread_cleanup_push.level = __ATEXIT__.length;
+ },
+
// ==========================================================================
// malloc.h
// ==========================================================================
@@ -6833,6 +6943,18 @@ LibraryManager.library = {
return eval(Pointer_stringify(ptr));
},
+ emscripten_run_script_string: function(ptr) {
+ var s = eval(Pointer_stringify(ptr));
+ var me = _emscripten_run_script_string;
+ if (!me.bufferSize || me.bufferSize < s.length+1) {
+ if (me.bufferSize) _free(me.buffer);
+ me.bufferSize = s.length+1;
+ me.buffer = _malloc(me.bufferSize);
+ }
+ writeStringToMemory(s, me.buffer);
+ return me.buffer;
+ },
+
emscripten_random: function() {
return Math.random();
},
diff --git a/src/library_gc.js b/src/library_gc.js
index bf0a6aff..a06e2f01 100644
--- a/src/library_gc.js
+++ b/src/library_gc.js
@@ -16,6 +16,11 @@ if (GC_SUPPORT) {
init: function() {
assert(!GC.initted);
GC.initted = true;
+
+ _GC_finalize_on_demand = _malloc(4); setValue(_GC_finalize_on_demand, 0, 'i32')
+ _GC_java_finalization = _malloc(4); setValue(_GC_java_finalization, 0, 'i32');
+ _GC_finalizer_notifier = _malloc(4); setValue(_GC_finalizer_notifier, 0, 'i32');
+
if (ENVIRONMENT_IS_WEB) {
setInterval(function() {
GC.maybeCollect();
@@ -159,7 +164,13 @@ if (GC_SUPPORT) {
GC_FORCE_COLLECT__deps: ['$GC'],
GC_FORCE_COLLECT: function() {
GC.collect();
- }
+ },
+
+ GC_finalize_on_demand: 0,
+ GC_java_finalization: 0,
+ GC_finalizer_notifier: 0,
+
+ GC_enable_incremental: function(){},
};
mergeInto(LibraryManager.library, LibraryGC);
diff --git a/src/library_gl.js b/src/library_gl.js
index 4d83572e..b4098813 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -454,8 +454,7 @@ var LibraryGL = {
},
glBufferSubData: function(target, offset, size, data) {
- var floatArray = {{{ makeHEAPView('F32', 'data', 'data+size') }}};
- Module.ctx.bufferSubData(target, offset, floatArray);
+ Module.ctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size));
},
glIsBuffer: function(buffer) {
diff --git a/src/modules.js b/src/modules.js
index 60b4ff87..9ef87691 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -5,11 +5,11 @@
var LLVM = {
LINKAGES: set('private', 'linker_private', 'linker_private_weak', 'linker_private_weak_def_auto', 'internal',
'available_externally', 'linkonce', 'common', 'weak', 'appending', 'extern_weak', 'linkonce_odr',
- 'weak_odr', 'externally_visible', 'dllimport', 'dllexport', 'unnamed_addr'),
+ 'weak_odr', 'externally_visible', 'dllimport', 'dllexport', 'unnamed_addr', 'thread_local'),
VISIBILITIES: set('default', 'hidden', 'protected'),
PARAM_ATTR: set('noalias', 'signext', 'zeroext', 'inreg', 'sret', 'nocapture', 'nest'),
FUNC_ATTR: set('hidden', 'nounwind', 'define', 'inlinehint', '{'),
- CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10', 'x86_fastcallcc', 'x86_stdcallcc'),
+ CALLING_CONVENTIONS: set('ccc', 'fastcc', 'coldcc', 'cc10', 'x86_fastcallcc', 'x86_stdcallcc', 'cc11'),
ACCESS_OPTIONS: set('volatile', 'atomic'),
INVOKE_MODIFIERS: set('alignstack', 'alwaysinline', 'inlinehint', 'naked', 'noimplicitfloat', 'noinline', 'alwaysinline attribute.', 'noredzone', 'noreturn', 'nounwind', 'optsize', 'readnone', 'readonly', 'ssp', 'sspreq'),
SHIFTS: set('ashr', 'lshr', 'shl'),
@@ -207,8 +207,9 @@ var Types = {
needAnalysis: {}, // Types noticed during parsing, that need analysis
- preciseI64MathUsed: false // Set to true if we actually use precise i64 math: If PRECISE_I64_MATH is set, and also such math is actually
- // needed (+,-,*,/,% - we do not need it for bitops)
+ // Set to true if we actually use precise i64 math: If PRECISE_I64_MATH is set, and also such math is actually
+ // needed (+,-,*,/,% - we do not need it for bitops), or PRECISE_I64_MATH is 2 (forced)
+ preciseI64MathUsed: (PRECISE_I64_MATH == 2)
};
var Functions = {
@@ -242,16 +243,14 @@ var Functions = {
for (var ident in this.indexedFunctions) {
vals[this.indexedFunctions[ident]] = ident;
}
-
// Resolve multi-level aliases all the way down
for (var i = 0; i < vals.length; i++) {
while (1) {
var varData = Variables.globals[vals[i]];
if (!(varData && varData.resolvedAlias)) break;
- vals[i] = vals[varData.resolvedAlias];
+ vals[i] = vals[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6
}
}
-
var indices = vals.toString().replace('"', '');
if (BUILD_AS_SHARED_LIB) {
// Shared libraries reuse the parent's function table.
@@ -302,11 +301,21 @@ function cDefine(key) {
var PassManager = {
serialize: function() {
- print('\n//FORWARDED_DATA:' + JSON.stringify({
- Types: Types,
- Variables: Variables,
- Functions: Functions
- }));
+ if (phase == 'pre') {
+ print('\n//FORWARDED_DATA:' + JSON.stringify({
+ Types: Types,
+ Variables: Variables,
+ Functions: Functions
+ }));
+ } else if (phase == 'funcs') {
+ print('\n//FORWARDED_DATA:' + JSON.stringify({
+ Types: { preciseI64MathUsed: Types.preciseI64MathUsed },
+ Functions: {
+ blockAddresses: Functions.blockAddresses,
+ indexedFunctions: Functions.indexedFunctions
+ }
+ }));
+ }
},
load: function(json) {
var data = JSON.parse(json);
diff --git a/src/parseTools.js b/src/parseTools.js
index 6a10176c..c70b511a 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -167,7 +167,15 @@ function isFunctionDef(token, out) {
return !fail;
}
+
+function isPossiblyFunctionType(type) {
+ // A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite.
+ var len = type.length;
+ return type[len-2] == ')' && type[len-1] == '*';
+}
+
function isFunctionType(type, out) {
+ if (!isPossiblyFunctionType(type)) return false;
type = type.replace(/"[^"]+"/g, '".."');
var parts;
// hackish, but quick splitting of function def parts. this must be fast as it happens a lot
@@ -184,14 +192,12 @@ function isFunctionType(type, out) {
return isType(parts[0]) && isFunctionDef({ text: text, item: tokenize(text.substr(1, text.length-2), true) }, out);
}
-function isType(type) { // TODO!
- return isVoidType(type) || Runtime.isNumberType(type) || isStructType(type) || isPointerType(type) || isFunctionType(type);
-}
-
-function isPossiblyFunctionType(type) {
- // A quick but unreliable way to see if something is a function type. Yes is just 'maybe', no is definite.
- var suffix = ')*';
- return type.substr(-suffix.length) == suffix;
+var isTypeCache = {}; // quite hot, optimize as much as possible
+function isType(type) {
+ if (type in isTypeCache) return isTypeCache[type];
+ var ret = isPointerType(type) || isVoidType(type) || Runtime.isNumberType(type) || isStructType(type) || isFunctionType(type);
+ isTypeCache[type] = ret;
+ return ret;
}
function isVarArgsFunctionType(type) {
@@ -875,7 +881,6 @@ function correctRoundings() {
}
function checkSpecificSafeHeap() {
- assert(!(SAFE_HEAP >= 2 && !Debugging.on), 'Need debugging for line-specific checks');
if (!Framework.currItem) return false;
return (SAFE_HEAP === 2 && Debugging.getIdentifier() in SAFE_HEAP_LINES) ||
(SAFE_HEAP === 3 && !(Debugging.getIdentifier() in SAFE_HEAP_LINES));
@@ -1997,9 +2002,7 @@ function parseBlockAddress(segment) {
}
function finalizeBlockAddress(param) {
- assert(param.func in Functions.blockAddresses);
- assert(param.label in Functions.blockAddresses[param.func]);
- return Functions.blockAddresses[param.func][param.label];
+ return '{{{ BA_' + param.func + '|' + param.label + ' }}}'; // something python will replace later
}
function stripCorrections(param) {
diff --git a/src/preamble.js b/src/preamble.js
index 16865bd0..d2bbc6a4 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -544,6 +544,9 @@ function Pointer_stringify(ptr, /* optional */ length) {
var i = 0;
var t;
while (1) {
+#if ASSERTIONS
+ assert(i < TOTAL_MEMORY);
+#endif
t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}};
if (nullTerminated && t == 0) break;
ret += utf8.processCChar(t);
@@ -602,26 +605,26 @@ function enlargeMemory() {
}
#if USE_TYPED_ARRAYS == 1
var oldIHEAP = IHEAP;
- HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
+ Module['HEAP'] = Module['IHEAP'] = HEAP = IHEAP = new Int32Array(TOTAL_MEMORY);
IHEAP.set(oldIHEAP);
IHEAPU = new Uint32Array(IHEAP.buffer);
#if USE_FHEAP
var oldFHEAP = FHEAP;
- FHEAP = new Float64Array(TOTAL_MEMORY);
+ Module['FHEAP'] = FHEAP = new Float64Array(TOTAL_MEMORY);
FHEAP.set(oldFHEAP);
#endif
#endif
#if USE_TYPED_ARRAYS == 2
var oldHEAP8 = HEAP8;
var buffer = new ArrayBuffer(TOTAL_MEMORY);
- HEAP8 = new Int8Array(buffer);
- HEAP16 = new Int16Array(buffer);
- HEAP32 = new Int32Array(buffer);
- HEAPU8 = new Uint8Array(buffer);
- HEAPU16 = new Uint16Array(buffer);
- HEAPU32 = new Uint32Array(buffer);
- HEAPF32 = new Float32Array(buffer);
- HEAPF64 = new Float64Array(buffer);
+ Module['HEAP8'] = HEAP8 = new Int8Array(buffer);
+ Module['HEAP16'] = HEAP16 = new Int16Array(buffer);
+ Module['HEAP32'] = HEAP32 = new Int32Array(buffer);
+ Module['HEAPU8'] = HEAPU8 = new Uint8Array(buffer);
+ Module['HEAPU16'] = HEAPU16 = new Uint16Array(buffer);
+ Module['HEAPU32'] = HEAPU32 = new Uint32Array(buffer);
+ Module['HEAPF32'] = HEAPF32 = new Float32Array(buffer);
+ Module['HEAPF64'] = HEAPF64 = new Float64Array(buffer);
HEAP8.set(oldHEAP8);
#endif
#endif
@@ -750,7 +753,11 @@ function exitRuntime() {
function String_len(ptr) {
var i = ptr;
- while ({{{ makeGetValue('i++', '0', 'i8') }}}) {}; // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
+ while ({{{ makeGetValue('i++', '0', 'i8') }}}) { // Note: should be |!= 0|, technically. But this helps catch bugs with undefineds
+#if ASSERTIONS
+ assert(i < TOTAL_MEMORY);
+#endif
+ }
return i - ptr - 1;
}
Module['String_len'] = String_len;
diff --git a/src/settings.js b/src/settings.js
index 58635950..5dc1e2eb 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -88,6 +88,10 @@ var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which i
// Note that we do not catch 32-bit multiplication by default (which must be done in
// 64 bits for high values for full precision) - you must manually set PRECISE_I32_MUL
// for that.
+ // If set to 2, we always include the i64 math code, which is necessary in the case
+ // that we can't know at compile time that 64-bit math is needed. For example, if you
+ // print 64-bit values with printf, but never add them, we can't know at compile time
+ // and you need to set this to 2.
var PRECISE_I32_MUL = 0; // If enabled, i64 math is done in i32 multiplication. This is necessary if the values
// exceed the JS double-integer limit of ~52 bits. This option can normally be disabled
// because generally i32 multiplication works ok without it, and enabling it has a big
@@ -192,6 +196,7 @@ var PGO = 0; // Profile-guided optimization.
var PROFILE = 0; // Enables runtime profiling. See test_profiling for a usage example.
+var EXPORT_ALL = 0; // If true, we export all the symbols
var EXPORTED_FUNCTIONS = ['_main', '_malloc', '_free']; // Functions that are explicitly exported, so they are guaranteed to
// be accessible outside of the generated code even after running closure compiler.
// Note the necessary prefix of "_".
diff --git a/src/utility.js b/src/utility.js
index 632ee08c..f3ece90b 100644
--- a/src/utility.js
+++ b/src/utility.js
@@ -184,7 +184,7 @@ function dprint() {
text = text(); // Allows deferred calculation, so dprints don't slow us down when not needed
}
text = DPRINT_INDENT + '// ' + text;
- print(text);
+ printErr(text);
}
var PROF_ORIGIN = Date.now();