diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 2 | ||||
-rw-r--r-- | src/intertyper.js | 6 | ||||
-rw-r--r-- | src/jsifier.js | 70 | ||||
-rw-r--r-- | src/library.js | 188 | ||||
-rw-r--r-- | src/library_gc.js | 13 | ||||
-rw-r--r-- | src/library_gl.js | 3 | ||||
-rw-r--r-- | src/modules.js | 33 | ||||
-rw-r--r-- | src/parseTools.js | 27 | ||||
-rw-r--r-- | src/preamble.js | 29 | ||||
-rw-r--r-- | src/settings.js | 5 | ||||
-rw-r--r-- | src/utility.js | 2 |
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(); |