diff --git a/emcc b/emcc index 92b1b537fb183..041c9982c84e1 100755 --- a/emcc +++ b/emcc @@ -928,19 +928,13 @@ try: fastcomp_opts += ['-emscripten-asyncify-functions=' + ','.join(shared.Settings.ASYNCIFY_FUNCTIONS)] fastcomp_opts += ['-emscripten-asyncify-whitelist=' + ','.join(shared.Settings.ASYNCIFY_WHITELIST)] - if shared.Settings.CORRECT_SIGNS != 1: - logging.warning('setting CORRECT_SIGNS to 1 for asm.js code generation') - shared.Settings.CORRECT_SIGNS = 1 - if shared.Settings.CORRECT_OVERFLOWS != 1: - logging.warning('setting CORRECT_OVERFLOWS to 1 for asm.js code generation') - shared.Settings.CORRECT_OVERFLOWS = 1 assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode' if shared.Settings.SAFE_HEAP and not js_opts: js_opts = True logging.warning('enabling js opts for SAFE_HEAP') - if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2 or shared.Settings.SAFE_HEAP >= 2: + if shared.Settings.SAFE_HEAP >= 2: debug_level = 4 # must keep debug info to do line-by-line operations if debug_level > 1 and closure: @@ -993,7 +987,7 @@ try: else: logging.debug('using response file for EXPORTED_FUNCTIONS, make sure it includes _malloc and _free') - if shared.Settings.ASM_JS and shared.Settings.RELOCATABLE: + if shared.Settings.RELOCATABLE: assert shared.Settings.DISABLE_EXCEPTION_CATCHING, 'no exceptions support with relocatable modules yet' assert not (bind and shared.Settings.NO_DYNAMIC_EXECUTION), 'NO_DYNAMIC_EXECUTION disallows embind' @@ -1392,10 +1386,9 @@ try: def run_passes(passes, title, just_split, just_concat): global final, minify_whitespace, emit_symbol_map, target - if shared.Settings.ASM_JS: - passes = ['asm'] + passes - if shared.Settings.PRECISE_F32: - passes = ['asmPreciseF32'] + passes + passes = ['asm'] + passes + if shared.Settings.PRECISE_F32: + passes = ['asmPreciseF32'] + passes if emit_symbol_map and 'minifyNames' in passes: passes += ['symbolMap='+target+'.symbols'] if profiling_funcs and 'minifyNames' in passes: @@ -1488,40 +1481,30 @@ try: if shared.Settings.PRECISE_F32: js_optimizer_queue += ['optimizeFrounds'] - if closure and not shared.Settings.ASM_JS: - flush_js_optimizer_queue() - - logging.debug('running closure') - # no need to add this to js_transform_tempfiles, because closure and - # debug_level > 0 are never simultaneously true - final = shared.Building.closure_compiler(final) - if DEBUG: save_intermediate('closure') - def do_minify(): global js_optimizer_queue if opt_level >= 2: - if debug_level < 2 and shared.Settings.ASM_JS and not closure == 2: + if debug_level < 2 and not closure == 2: js_optimizer_queue += ['minifyNames'] if debug_level == 0: global minify_whitespace minify_whitespace = True - if shared.Settings.ASM_JS: - if closure == 1: - js_optimizer_queue += ['closure'] - elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and shared.Settings.FINALIZE_ASM_JS and not closure: - js_optimizer_queue += ['cleanup'] + if closure == 1: + js_optimizer_queue += ['closure'] + elif debug_level <= 2 and not shared.Settings.MAIN_MODULE and shared.Settings.FINALIZE_ASM_JS and not closure: + js_optimizer_queue += ['cleanup'] if js_opts: - if shared.Settings.ASM_JS and shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap'] + if shared.Settings.SAFE_HEAP: js_optimizer_queue += ['safeHeap'] - if shared.Settings.OUTLINING_LIMIT > 0 and shared.Settings.ASM_JS: + if shared.Settings.OUTLINING_LIMIT > 0: js_optimizer_queue += ['outline'] js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT - if opt_level >= 2 and (not closure or shared.Settings.ASM_JS or closure == 2) and debug_level < 3: - if shared.Settings.ASM_JS and (opt_level >= 3 or shrink_level > 0): + if opt_level >= 2 and debug_level < 3: + if opt_level >= 3 or shrink_level > 0: js_optimizer_queue += ['registerizeHarder'] else: js_optimizer_queue += ['registerize'] @@ -1529,14 +1512,14 @@ try: if not shared.Settings.EMTERPRETIFY: do_minify() - if opt_level >= 2 and shared.Settings.ASM_JS: + if opt_level >= 2: js_optimizer_queue += ['asmLastOpts'] if shared.Settings.FINALIZE_ASM_JS: js_optimizer_queue += ['last'] flush_js_optimizer_queue() - if shared.Settings.ASM_JS and closure == 2: + if closure == 2: flush_js_optimizer_queue() logging.debug('running closure') diff --git a/emscripten.py b/emscripten.py index 2f6dce4489b62..1f6dd0dead847 100755 --- a/emscripten.py +++ b/emscripten.py @@ -104,7 +104,11 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, funcs = backend_output[start_funcs+len(start_funcs_marker):end_funcs] metadata_raw = backend_output[metadata_split+len(metadata_split_marker):] #if DEBUG: print >> sys.stderr, "METAraw", metadata_raw - metadata = json.loads(metadata_raw) + try: + metadata = json.loads(metadata_raw) + except Exception, e: + logging.error('emscript: failure to parse metadata output from compiler backend. raw output is: \n' + metadata_raw) + raise e mem_init = backend_output[end_funcs+len(end_funcs_marker):metadata_split] #if DEBUG: print >> sys.stderr, "FUNCS", funcs #if DEBUG: print >> sys.stderr, "META", metadata @@ -187,7 +191,7 @@ def save_settings(): # Call js compiler if DEBUG: t = time.time() out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, - [settings_file, ';', 'glue'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, + [settings_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, cwd=path_from_root('src'), error_limit=300) assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?' glue, forwarded_data = out.split('//FORWARDED_DATA:') @@ -202,10 +206,6 @@ def save_settings(): last_forwarded_json['Functions']['tables'] = metadata['tables'] - '''indexed_functions = set() - for key in forwarded_json['Functions']['indexedFunctions'].iterkeys(): - indexed_functions.add(key)''' - pre, post = glue.split('// EMSCRIPTEN_END_FUNCS') #print >> sys.stderr, 'glue:', pre, '\n\n||||||||||||||||\n\n', post, '...............' diff --git a/site/source/get_api_items_py b/site/source/get_api_items.py similarity index 98% rename from site/source/get_api_items_py rename to site/source/get_api_items.py index 2049286d24028..53ceb68d54824 100644 --- a/site/source/get_api_items_py +++ b/site/source/get_api_items.py @@ -21,7 +21,7 @@ #the directory, relative to \source for the API reference -api_reference_directory = '.\\docs\\api_reference\\' +api_reference_directory = './docs/api_reference/' #name to write API items to. Note, this is used by the get-wiki.py script, so if you change here, change everywhere. api_item_filename = 'api_items.py' diff --git a/site/source/get_wiki.py b/site/source/get_wiki.py index 5c7214cdaa4b3..5d7550c782c64 100644 --- a/site/source/get_wiki.py +++ b/site/source/get_wiki.py @@ -24,7 +24,7 @@ wiki_repo = 'https://github.com/kripken/emscripten.wiki.git' -wiki_directory = '.\\wiki_static\\' +wiki_directory = './wiki_static/' logfilename='log-get-wiki.txt' @@ -45,7 +45,7 @@ -wiki_temp_directory = wiki_directory + 'temp\\' +wiki_temp_directory = wiki_directory + 'temp/' temp_set_of_codemarkup=set() logfile=open(logfilename,'w') #snapshot_version_information='.. note:: This is a **snapshot** of the wiki: %s\n\n' % strftime("%a, %d %b %Y %H:%M", gmtime()) diff --git a/src/compiler.js b/src/compiler.js index 65da1b6a2dfb4..a53712619725a 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -132,14 +132,7 @@ load('utility.js'); load('settings.js'); var settings_file = arguments_[0]; -var ll_file = arguments_[1]; -phase = arguments_[2]; -if (phase == 'pre' || phase == 'glue') { - additionalLibraries = Array.prototype.slice.call(arguments_, 3); -} else { - var forwardedDataFile = arguments_[3]; - additionalLibraries = Array.prototype.slice.call(arguments_, 4); -} +additionalLibraries = Array.prototype.slice.call(arguments_, 1); if (settings_file) { var settings = JSON.parse(read(settings_file)); @@ -158,15 +151,6 @@ if (settings_file) { } -if (CORRECT_SIGNS >= 2) { - CORRECT_SIGNS_LINES = set(CORRECT_SIGNS_LINES); // for fast checking -} -if (CORRECT_OVERFLOWS >= 2) { - CORRECT_OVERFLOWS_LINES = set(CORRECT_OVERFLOWS_LINES); // for fast checking -} -if (CORRECT_ROUNDINGS >= 2) { - CORRECT_ROUNDINGS_LINES = set(CORRECT_ROUNDINGS_LINES); // for fast checking -} if (SAFE_HEAP >= 2) { SAFE_HEAP_LINES = set(SAFE_HEAP_LINES); // for fast checking } @@ -196,19 +180,6 @@ assert(!(!NAMED_GLOBALS && BUILD_AS_SHARED_LIB), 'shared libraries must have nam // Output some info and warnings based on settings -if (phase == 'pre') { - if (!MICRO_OPTS || 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, http://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html'); - } - - 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.'); - } -} - if (VERBOSE) printErr('VERBOSE is on, this generates a lot of output and can slow down compilation'); if (!BOOTSTRAPPING_STRUCT_INFO) { @@ -241,20 +212,18 @@ Runtime.QUANTUM_SIZE = QUANTUM_SIZE; B = new Benchmarker(); try { - if (ll_file) { - var dummyData = {functionStubs: []} - JSify(dummyData); - - //dumpInterProf(); - //printErr(phase + ' paths (fast, slow): ' + [fastPaths, slowPaths]); - B.print(phase); - - if (DEBUG_MEMORY) { - print('zzz. last gc: ' + gc()); - MemoryDebugger.dump(); - print('zzz. hanging now!'); - while(1){}; - } + var dummyData = {functionStubs: []} + JSify(dummyData); + + //dumpInterProf(); + //printErr('paths (fast, slow): ' + [fastPaths, slowPaths]); + B.print('glue'); + + if (DEBUG_MEMORY) { + print('zzz. last gc: ' + gc()); + MemoryDebugger.dump(); + print('zzz. hanging now!'); + while(1){}; } } catch(err) { if (err.toString().indexOf('Aborting compilation due to previous errors') != -1) { diff --git a/src/emrun_postjs.js b/src/emrun_postjs.js index 4f20d479e570a..6a3f6e66f444e 100644 --- a/src/emrun_postjs.js +++ b/src/emrun_postjs.js @@ -11,8 +11,8 @@ function emrun_register_handlers() { var prevErr = Module['printErr']; function emrun_exit() { post('^exit^'+EXITSTATUS); }; Module['addOnExit'](emrun_exit); - Module['print'] = function emrun_print(text) { post('^out^'+(emrun_http_sequence_number++)+'^'+text); prevPrint(text); } - Module['printErr'] = function emrun_printErr(text) { post('^err^'+(emrun_http_sequence_number++)+'^'+text); prevErr(text); } + Module['print'] = function emrun_print(text) { post('^out^'+(emrun_http_sequence_number++)+'^'+encodeURIComponent(text)); prevPrint(text); } + Module['printErr'] = function emrun_printErr(text) { post('^err^'+(emrun_http_sequence_number++)+'^'+encodeURIComponent(text)); prevErr(text); } } // Notify emrun web server that this browser has successfully launched the page. post('^pageload^'); diff --git a/src/jsifier.js b/src/jsifier.js index d2664f20b5700..10b0174cbcc6d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -26,32 +26,30 @@ function JSify(data, functionsOnly) { if (mainPass) { var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js'); - if (phase == 'glue') { - // We will start to print out the data, but must do so carefully - we are - // dealing with potentially *huge* strings. Convenient replacements and - // manipulations may create in-memory copies, and we may OOM. - // - // Final shape that will be created: - // shell - // (body) - // preamble - // runtime - // generated code - // postamble - // global_vars - // - // First, we print out everything until the generated code. Then the - // functions will print themselves out as they are parsed. Finally, we - // will call finalCombiner in the main pass, to print out everything - // else. This lets us not hold any strings in memory, we simply print - // things out as they are ready. - - var shellParts = read(shellFile).split('{{BODY}}'); - print(processMacros(preprocess(shellParts[0]))); - var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js'; - var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()))); - print(pre); - } + // We will start to print out the data, but must do so carefully - we are + // dealing with potentially *huge* strings. Convenient replacements and + // manipulations may create in-memory copies, and we may OOM. + // + // Final shape that will be created: + // shell + // (body) + // preamble + // runtime + // generated code + // postamble + // global_vars + // + // First, we print out everything until the generated code. Then the + // functions will print themselves out as they are parsed. Finally, we + // will call finalCombiner in the main pass, to print out everything + // else. This lets us not hold any strings in memory, we simply print + // things out as they are ready. + + var shellParts = read(shellFile).split('{{BODY}}'); + print(processMacros(preprocess(shellParts[0]))); + var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js'; + var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime()))); + print(pre); } if (mainPass) { @@ -61,31 +59,29 @@ function JSify(data, functionsOnly) { LibraryManager.load(); //B.stop('jsifier-libload'); - if (phase == 'glue') { - var libFuncsToInclude; - if (INCLUDE_FULL_LIBRARY) { - assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.') - libFuncsToInclude = MAIN_MODULE ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.slice(0) : []; - for (var key in LibraryManager.library) { - if (!key.match(/__(deps|postset|inline|asm|sig)$/)) { - libFuncsToInclude.push(key); - } + var libFuncsToInclude; + if (INCLUDE_FULL_LIBRARY) { + assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.') + libFuncsToInclude = MAIN_MODULE ? DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.slice(0) : []; + for (var key in LibraryManager.library) { + if (!key.match(/__(deps|postset|inline|asm|sig)$/)) { + libFuncsToInclude.push(key); } - } else { - libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE; } - libFuncsToInclude.forEach(function(ident) { - var finalName = '_' + ident; - if (ident[0] === '$') { - finalName = ident.substr(1); - } - data.functionStubs.push({ - intertype: 'functionStub', - finalName: finalName, - ident: '_' + ident - }); - }); + } else { + libFuncsToInclude = DEFAULT_LIBRARY_FUNCS_TO_INCLUDE; } + libFuncsToInclude.forEach(function(ident) { + var finalName = '_' + ident; + if (ident[0] === '$') { + finalName = ident.substr(1); + } + data.functionStubs.push({ + intertype: 'functionStub', + finalName: finalName, + ident: '_' + ident + }); + }); } function processLibraryFunction(snippet, ident, finalName) { @@ -208,8 +204,7 @@ function JSify(data, functionsOnly) { Functions.libraryFunctions[finalName] = 2; } if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent - if ((phase == 'glue') && - (EXPORT_ALL || (finalName in EXPORTED_FUNCTIONS))) { + if (EXPORT_ALL || (finalName in EXPORTED_FUNCTIONS)) { contentText += '\nModule["' + finalName + '"] = ' + finalName + ';'; } return depsText + contentText; @@ -275,7 +270,7 @@ function JSify(data, functionsOnly) { // if (!mainPass) { - if ((phase == 'glue') && !Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) { + if (!Variables.generatedGlobalBase && !BUILD_AS_SHARED_LIB) { Variables.generatedGlobalBase = true; // Globals are done, here is the rest of static memory if (!SIDE_MODULE) { @@ -289,97 +284,85 @@ function JSify(data, functionsOnly) { var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable); print(generated.map(function(item) { return item.JS; }).join('\n')); - if (phase == 'glue') { - if (memoryInitialization.length > 0) { - // apply postsets directly into the big memory initialization - itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { - var m; - if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d{}\w_' ]+);?$/.exec(item.JS)) { - var type = getTypeFromHeap(m[1]); - var bytes = Runtime.getNativeTypeSize(type); - var target = eval(m[2]) << log2(bytes); - var value = m[3]; - try { - value = eval(value); - } catch(e) { - // possibly function table {{{ FT_* }}} etc. - if (value.indexOf('{{ ') < 0) return true; - } - writeInt8s(memoryInitialization, target - Runtime.GLOBAL_BASE, value, type); - return false; + if (memoryInitialization.length > 0) { + // apply postsets directly into the big memory initialization + itemsDict.GlobalVariablePostSet = itemsDict.GlobalVariablePostSet.filter(function(item) { + var m; + if (m = /^HEAP([\dFU]+)\[([()>\d]+)\] *= *([()|\d{}\w_' ]+);?$/.exec(item.JS)) { + var type = getTypeFromHeap(m[1]); + var bytes = Runtime.getNativeTypeSize(type); + var target = eval(m[2]) << log2(bytes); + var value = m[3]; + try { + value = eval(value); + } catch(e) { + // possibly function table {{{ FT_* }}} etc. + if (value.indexOf('{{ ') < 0) return true; } - return true; - }); - // write out the singleton big memory initialization value - print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE' + (SIDE_MODULE ? '+H_BASE' : ''), true)); - } else if (phase !== 'glue') { - print('/* no memory initializer */'); // test purposes - } - - if (phase !== 'glue') { - // Define postsets. These will be run in ATINIT, right before global initializers (which might need the postsets). We cannot - // run them now because the memory initializer might not have been applied yet. - print('function runPostSets() {\n'); - print(itemsDict.GlobalVariablePostSet.map(function(item) { return item.JS }).join('\n')); - print('}\n'); - } + 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', 'Runtime.GLOBAL_BASE' + (SIDE_MODULE ? '+H_BASE' : ''), true)); + } else { + print('/* no memory initializer */'); // test purposes + } - if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { - 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'); - } + if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { + 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; } // Print out global variables and postsets TODO: batching - if (phase == 'glue') { - var legalizedI64sDefault = legalizedI64s; - legalizedI64s = false; + var legalizedI64sDefault = legalizedI64s; + legalizedI64s = false; - var globalsData = {functionStubs: []} - JSify(globalsData, true); - globalsData = null; + var globalsData = {functionStubs: []} + JSify(globalsData, true); + globalsData = null; - var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet); - generated.forEach(function(item) { print(indentify(item.JS || '', 2)); }); + var generated = itemsDict.functionStub.concat(itemsDict.GlobalVariablePostSet); + generated.forEach(function(item) { print(indentify(item.JS || '', 2)); }); - legalizedI64s = legalizedI64sDefault; + legalizedI64s = legalizedI64sDefault; - if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { - 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, "TOTAL_MEMORY not big enough for stack");\n'); - } + if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { + 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, "TOTAL_MEMORY not big enough for stack");\n'); + } - if (asmLibraryFunctions.length > 0) { - 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 } XXX assumes function has multiple lines - return f + '}'; // add unindented } to match function - } - print(asmLibraryFunctions.map(fix).join('\n')); + if (asmLibraryFunctions.length > 0) { + 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 } XXX assumes function has multiple lines + return f + '}'; // add unindented } to match function } + print(asmLibraryFunctions.map(fix).join('\n')); } if (abortExecution) throw 'Aborting compilation due to previous errors'; @@ -393,10 +376,10 @@ function JSify(data, functionsOnly) { ['i64Add', 'i64Subtract', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr', 'llvm_cttz_i32'].forEach(function(ident) { var finalName = '_' + ident; - if (!Functions.libraryFunctions[finalName] || (phase == 'glue' && ident[0] === 'l' && !addedLibraryItems[ident])) { // TODO: one-by-one in fastcomp glue mode + if (!Functions.libraryFunctions[finalName] || (ident[0] === 'l' && !addedLibraryItems[ident])) { // TODO: one-by-one in fastcomp glue mode print(processLibraryFunction(LibraryManager.library[ident], ident, finalName)); // must be first to be close to generated code Functions.implementedFunctions[finalName] = LibraryManager.library[ident + '__sig']; - Functions.libraryFunctions[finalName] = phase == 'glue' ? 2 : 1; // XXX + Functions.libraryFunctions[finalName] = 2; // XXX // limited dependency handling var deps = LibraryManager.library[ident + '__deps']; if (deps) { @@ -446,8 +429,6 @@ function JSify(data, functionsOnly) { var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}'); print(postParts[0]); - Functions.generateIndexing(); // done last, as it may rely on aliases set in postsets - // Load runtime-linked libraries RUNTIME_LINKED_LIBS.forEach(function(lib) { print('eval(Module["read"]("' + lib + '"))(' + Functions.getTable('x') + '.length, this);'); diff --git a/src/library_async.js b/src/library_async.js index 03b3329d8e168..6742cbee8ec2c 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -253,7 +253,18 @@ mergeInto(LibraryManager.library, { Browser.resumeAsyncCallbacks(); // if we were paused (e.g. we are after a sleep), then since we are now yielding, it is safe to call callbacks } + var callingDoAsyncOp = 1; // if resume is called synchronously - during the doAsyncOp - we must make it truly async, for consistency + doAsyncOp(function resume(post) { + if (callingDoAsyncOp) { + assert(callingDoAsyncOp === 1); // avoid infinite recursion + callingDoAsyncOp++; + setTimeout(function() { + resume(post); + }, 0); + return; + } + assert(EmterpreterAsync.state === 1 || EmterpreterAsync.state === 3); EmterpreterAsync.setState(3); if (yieldDuring) { @@ -283,6 +294,9 @@ mergeInto(LibraryManager.library, { EmterpreterAsync.asyncFinalizers.length = 0; } }); + + callingDoAsyncOp = 0; + EmterpreterAsync.setState(1); #if ASSERTIONS EmterpreterAsync.saveStack = new Error().stack; // we can't call stackTrace() as it calls compiled code diff --git a/src/modules.js b/src/modules.js index 9abe198f07594..ed8764f8e37b8 100644 --- a/src/modules.js +++ b/src/modules.js @@ -246,7 +246,6 @@ var Functions = { libraryFunctions: {}, // functions added from the library. value 2 means asmLibraryFunction unimplementedFunctions: {}, // library etc. functions that we need to index, maps id to signature - indexedFunctions: {}, nextIndex: firstTableIndex, // Start at a non-0 (even, see below) value neededTables: set('v', 'vi', 'ii', 'iii'), // signatures that appeared (initialized with library stuff // we always use), and we will need a function table for @@ -295,118 +294,8 @@ var Functions = { return sig; }, - // Mark a function as needing indexing. Python will coordinate them all - getIndex: function(ident, sig) { - var ret; - if (phase != 'post' && singlePhase) { - ret = "'{{ FI_" + toNiceIdent(ident) + " }}'"; // something python will replace later - this.indexedFunctions[ident] = 0; - } else { - if (!singlePhase) return 'NO_INDEX'; // Should not index functions in post - ret = this.indexedFunctions[ident]; - assert(ret); - ret = ret.toString(); - } - if (SIDE_MODULE && sig) { // sig can be undefined for the GL library functions - ret = '((F_BASE_' + sig + ' + ' + ret + ')|0)'; - } else if (BUILD_AS_SHARED_LIB) { - ret = '(FUNCTION_TABLE_OFFSET + ' + ret + ')'; - } - return ret; - }, - getTable: function(sig) { return 'FUNCTION_TABLE_' + sig - }, - - // Generate code for function indexing - generateIndexing: function() { - var tables = { pre: '' }; - keys(Functions.neededTables).forEach(function(sig) { // add some default signatures that are used in the library - tables[sig] = zeros(firstTableIndex); - }); - for (var ident in this.indexedFunctions) { - var sig = Functions.implementedFunctions[ident] || Functions.unimplementedFunctions[ident] || LibraryManager.library[ident.substr(1) + '__sig']; - assert(sig, ident); - if (!tables[sig]) tables[sig] = zeros(firstTableIndex); - var index = this.indexedFunctions[ident]; - for (var i = tables[sig].length; i < index; i++) { - tables[sig][i] = 0; // keep flat - } - tables[sig][index] = ident; - } - var generated = false; - var wrapped = {}; // whether we wrapped a lib func - var maxTable = 0; - for (var t in tables) { - if (t == 'pre') continue; - generated = true; - var table = tables[t]; - for (var i = 0; i < table.length; i++) { - // Resolve multi-level aliases all the way down - while (1) { - var varData = Variables.globals[table[i]]; - if (!(varData && varData.resolvedAlias && !/(FUNCTION_TABLE_OFFSET|F_BASE_)/.test(varData.resolvedAlias))) break; - table[i] = table[+varData.resolvedAlias || eval(varData.resolvedAlias)]; // might need to eval to turn (6) into 6 - } - // Resolve library aliases - if (table[i]) { - var libName = LibraryManager.getRootIdent(table[i].substr(1)); - if (libName && typeof libName == 'string') { - table[i] = (libName.indexOf('Math_') < 0 ? '_' : '') + libName; - } - } - var curr = table[i]; - if (curr && curr != '0' && !Functions.implementedFunctions[curr]) { - var short = toNiceIdent(curr); // fix Math.* to Math_* - curr = t + '_' + short; // libfuncs can alias with different sigs, wrap each separately - // This is a library function, we can't just put it in the function table, need a wrapper - if (!wrapped[curr]) { - var args = '', arg_coercions = '', call = short + '(', retPre = '', retPost = ''; - if (t[0] != 'v') { - var temp = asmFFICoercion('X', Functions.getSignatureType(t[0])).split('X'); - retPre = 'return ' + temp[0]; - retPost = temp[1]; - } - for (var j = 1; j < t.length; j++) { - args += (j > 1 ? ',' : '') + 'a' + j; - var type = Functions.getSignatureType(t[j]); - arg_coercions += 'a' + j + '=' + asmCoercion('a' + j, type) + ';'; - call += (j > 1 ? ',' : '') + asmCoercion('a' + j, type === 'float' ? 'double' : type); // ffi arguments must be doubles if they are floats - } - call += ')'; - if (short == '_setjmp') printErr('WARNING: setjmp used via a function pointer. If this is for libc setjmp (not something of your own with the same name), it will break things'); - tables.pre += 'function ' + curr + '__wrapper(' + args + ') { ' + arg_coercions + ' ; ' + retPre + call + retPost + ' }\n'; - wrapped[curr] = 1; - } - table[i] = curr + '__wrapper'; - } - } - maxTable = Math.max(maxTable, table.length); - } - maxTable = ceilPowerOfTwo(maxTable); - for (var t in tables) { - if (t == 'pre') continue; - var table = tables[t]; - // asm function table mask must be power of two, and non-asm must be aligned - // if nonaliasing, then standardize function table size, to avoid aliasing pointers through the &M mask (in a small table using a big index) - var fullSize = ALIASING_FUNCTION_POINTERS ? ceilPowerOfTwo(table.length) : maxTable; - for (var i = table.length; i < fullSize; i++) { - table[i] = 0; - } - // finalize table - var indices = table.toString().replace('"', ''); - if (BUILD_AS_SHARED_LIB) { - // Shared libraries reuse the parent's function table. - tables[t] = Functions.getTable(t) + '.push.apply(' + Functions.getTable(t) + ', [' + indices + ']);\n'; - } else { - tables[t] = 'var ' + Functions.getTable(t) + ' = [' + indices + '];\n'; - if (SAFE_DYNCALLS) { - tables[t] += 'var FUNCTION_TABLE_NAMES = ' + JSON.stringify(table).replace(/\n/g, '').replace(/,0/g, ',0\n') + ';\n'; - } - } - } - Functions.tables = tables; } }; @@ -550,39 +439,10 @@ function cDefine(key) { var PassManager = { serialize: function() { - if (phase == 'pre') { - print('\n//FORWARDED_DATA:' + JSON.stringify({ - Types: Types, - Variables: Variables, - Functions: Functions, - EXPORTED_FUNCTIONS: EXPORTED_FUNCTIONS, // needed for asm.js global constructors (ctors) - Runtime: { GLOBAL_BASE: Runtime.GLOBAL_BASE } - })); - } else if (phase == 'funcs') { - print('\n//FORWARDED_DATA:' + JSON.stringify({ - Types: { - hasInlineJS: Types.hasInlineJS, - usesSIMD: Types.usesSIMD, - preciseI64MathUsed: Types.preciseI64MathUsed - }, - Functions: { - blockAddresses: Functions.blockAddresses, - indexedFunctions: Functions.indexedFunctions, - implementedFunctions: Functions.implementedFunctions, - unimplementedFunctions: Functions.unimplementedFunctions, - neededTables: Functions.neededTables - } - })); - } else if (phase == 'post') { - print('\n//FORWARDED_DATA:' + JSON.stringify({ - Functions: { tables: Functions.tables } - })); - } else if (phase == 'glue') { - print('\n//FORWARDED_DATA:' + JSON.stringify({ - Functions: Functions, - EXPORTED_FUNCTIONS: EXPORTED_FUNCTIONS - })); - } + print('\n//FORWARDED_DATA:' + JSON.stringify({ + Functions: Functions, + EXPORTED_FUNCTIONS: EXPORTED_FUNCTIONS + })); }, load: function(json) { var data = JSON.parse(json); @@ -597,7 +457,7 @@ var PassManager = { } EXPORTED_FUNCTIONS = data.EXPORTED_FUNCTIONS; /* - print('\n//LOADED_DATA:' + phase + ':' + JSON.stringify({ + print('\n//LOADED_DATA:' + JSON.stringify({ Types: Types, Variables: Variables, Functions: Functions diff --git a/src/parseTools.js b/src/parseTools.js index e7963e6b02437..796bd254bfed5 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -71,7 +71,6 @@ function preprocess(text) { return ret; } -function addPointing(type) { return type + '*' } function removePointing(type, num) { if (num === 0) return type; assert(type.substr(type.length-(num ? num : 1)).replace(/\*/g, '') === ''); //, 'Error in removePointing with ' + [type, num, type.substr(type.length-(num ? num : 1))]); @@ -169,16 +168,6 @@ function getStructuralTypeParts(type) { // split { i32, i8 } etc. into parts return type.replace(/[ {}]/g, '').split(','); } -function getStructureTypeParts(type) { - if (isStructuralType(type)) { - return type.replace(/[ {}]/g, '').split(','); - } else { - var typeData = Types.types[type]; - assert(typeData, type); - return typeData.fields; - } -} - function getStructuralTypePartBits(part) { return Math.ceil((getBits(part) || 32)/32)*32; // simple 32-bit alignment. || 32 is for pointers } @@ -321,103 +310,6 @@ function isType(type) { return ret; } -function isVarArgsFunctionType(type) { - // assumes this is known to be a function type already - var varArgsSuffix = '...)*'; - return type.substr(-varArgsSuffix.length) == varArgsSuffix; -} - -function getNumLegalizedVars(type) { // how many legalized variables are needed to represent this type - if (type in Compiletime.FLOAT_TYPES) return 1; - return Math.max(getNumIntChunks(type), 1); -} - -function countNormalArgs(type, out, legalized) { - out = out || {}; - if (!isFunctionType(type, out)) return -1; - var ret = 0; - if (out.segments) { - for (var i = 0; i < out.segments.length; i++) { - ret += legalized ? getNumLegalizedVars(out.segments[i][0].text) : 1; - } - } - if (isVarArgsFunctionType(type)) ret--; - return ret; -} - -function getVectorSize(type) { - return parseInt(type.substring(1, type.indexOf(' '))); -} - -function getVectorNativeType(type) { - Types.usesSIMD = true; - switch (type) { - case '<2 x float>': - case '<4 x float>': return 'float'; - case '<2 x i32>': - case '<4 x i32>': return 'i32'; - default: throw 'unknown vector type ' + type; - } -} - -function getSIMDName(type) { - switch (type) { - case 'i32': return 'int'; - case 'float': return 'float'; - default: throw 'getSIMDName ' + type; - } -} - -function getVectorBaseType(type) { - return getSIMDName(getVectorNativeType(type)); -} - -function addIdent(token) { - token.ident = token.text; - return token; -} - -function combineTokens(tokens) { - var ret = { - lineNum: tokens[0].lineNum, - text: '', - tokens: [] - }; - tokens.forEach(function(token) { - ret.text += token.text; - ret.tokens.push(token); - }); - return ret; -} - -function compareTokens(a, b) { - var aId = a.__uid__; - var bId = b.__uid__; - a.__uid__ = 0; - b.__uid__ = 0; - var ret = JSON.stringify(a) == JSON.stringify(b); - a.__uid__ = aId; - b.__uid__ = bId; - return ret; -} - -function getTokenIndexByText(tokens, text) { - var i = 0; - while (tokens[i] && tokens[i].text != text) i++; - return i; -} - -function findTokenText(item, text) { - return findTokenTextAfter(item, text, 0); -} - -function findTokenTextAfter(item, text, startAt) { - for (var i = startAt; i < item.tokens.length; i++) { - if (item.tokens[i].text == text) return i; - } - return -1; -} - var SPLIT_TOKEN_LIST_SPLITTERS = set(',', 'to'); // 'to' can separate parameters as well... // Splits a list of tokens separated by commas. For example, a list of arguments in a function call @@ -456,11 +348,6 @@ function isIndexableGlobal(ident) { return !data.alias && !data.external; } -function makeGlobalDef(ident) { - if (!NAMED_GLOBALS && isIndexableGlobal(ident)) return ''; - return 'var ' + ident + ';'; -} - function makeGlobalUse(ident) { if (!NAMED_GLOBALS && isIndexableGlobal(ident)) { var index = Variables.indexedGlobals[ident]; @@ -748,35 +635,6 @@ function parseLLVMString(str) { return ret; } -function expandLLVMString(str) { - return str.replace(/\\../g, function(m) { - return String.fromCharCode(parseInt(m.substr(1), '16')); - }); -} - -function getLabelIds(labels) { - return labels.map(function(label) { return label.ident }); -} - -function cleanLabel(label) { - if (label[0] == 'B') { - return label.substr(5); - } else { - return label; - } -} - -function getOldLabel(label) { - var parts = label.split('|'); - return parts[parts.length-1]; -} - -function calcAllocatedSize(type) { - var ret = Runtime.getNativeTypeSize(type); - if (ret) return ret; - return Types.types[type].flatSize; // known type -} - // Generates the type signature for a structure, for each byte, the type that is there. // i32, 0, 0, 0 - for example, an int32 is here, then nothing to do for the 3 next bytes, naturally function generateStructTypes(type) { @@ -849,34 +707,6 @@ function indentify(text, indent) { // Correction tools -function correctSpecificSign() { - if (!Framework.currItem) return false; - if (Framework.currItem.funcData.ident.indexOf('emscripten_autodebug') >= 0) return 1; // always correct in the autodebugger code! - return (CORRECT_SIGNS === 2 && Debugging.getIdentifier() in CORRECT_SIGNS_LINES) || - (CORRECT_SIGNS === 3 && !(Debugging.getIdentifier() in CORRECT_SIGNS_LINES)); -} -function correctSigns() { - return CORRECT_SIGNS === 1 || correctSpecificSign(); -} - -function correctSpecificOverflow() { - if (!Framework.currItem) return false; - return (CORRECT_OVERFLOWS === 2 && Debugging.getIdentifier() in CORRECT_OVERFLOWS_LINES) || - (CORRECT_OVERFLOWS === 3 && !(Debugging.getIdentifier() in CORRECT_OVERFLOWS_LINES)); -} -function correctOverflows() { - return CORRECT_OVERFLOWS === 1 || correctSpecificOverflow(); -} - -function correctSpecificRounding() { - if (!Framework.currItem) return false; - return (CORRECT_ROUNDINGS === 2 && Debugging.getIdentifier() in CORRECT_ROUNDINGS_LINES) || - (CORRECT_ROUNDINGS === 3 && !(Debugging.getIdentifier() in CORRECT_ROUNDINGS_LINES)); -} -function correctRoundings() { - return CORRECT_ROUNDINGS === 1 || correctSpecificRounding(); -} - function checkSpecificSafeHeap() { if (!Framework.currItem) return false; return (SAFE_HEAP === 2 && Debugging.getIdentifier() in SAFE_HEAP_LINES) || @@ -886,7 +716,7 @@ function checkSafeHeap() { return SAFE_HEAP === 1 || checkSpecificSafeHeap(); } -function getHeapOffset(offset, type, forceAsm) { +function getHeapOffset(offset, type) { if (Runtime.getNativeFieldSize(type) > 4) { if (type == 'i64') { type = 'i32'; // we emulate 64-bit integer values as 32 in asmjs-unknown-emscripten, but not double @@ -1046,12 +876,12 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - if (!ignore && phase !== 'funcs') { + if (!ignore) { return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type); } } - var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']'; - if (phase == 'funcs' || forceAsm) { + var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type) + ']'; + if (forceAsm) { ret = asmCoercion(ret, type); } if (ASM_HEAP_LOG) { @@ -1065,21 +895,6 @@ function makeGetValueAsm(ptr, pos, type, unsigned) { return makeGetValue(ptr, pos, type, null, unsigned, null, null, null, true); } -function indexizeFunctions(value, type) { - assert((type && type !== '?') || (typeof value === 'string' && value.substr(0, 6) === 'CHECK_'), 'No type given for function indexizing'); - assert(value !== type, 'Type set to value'); - var out = {}; - if (type && isFunctionType(type, out) && value[0] === '_') { // checking for _ differentiates from $ (local vars) - // add signature to library functions that we now know need indexing - var sig = Functions.implementedFunctions[value] || Functions.unimplementedFunctions[value]; - if (!sig) { - sig = Functions.unimplementedFunctions[value] = Functions.getSignature(out.returnType, out.segments ? out.segments.map(function(segment) { return segment[0].text }) : [], isVarArgsFunctionType(type)); - } - return Functions.getIndex(value, sig); - } - return value; -} - //! @param ptr The pointer. Used to find both the slab and the offset in that slab. If the pointer //! is just an integer, then this is almost redundant, but in general the pointer type //! may in the future include information about which slab as well. So, for now it is @@ -1148,18 +963,16 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, } } - value = indexizeFunctions(value, type); var offset = calcFastOffset(ptr, pos, noNeedFirst); - if (phase === 'pre' && isNumber(offset)) offset += ' '; // avoid pure numeric strings, seem to be perf issues with overly-aggressive interning or slt in pre processing of heap inits if (SAFE_HEAP && !noSafe) { var printType = type; if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"'; if (printType[0] === '#') printType = printType.substr(1); - if (!ignore && phase !== 'funcs') { + if (!ignore) { return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Compiletime.FLOAT_TYPES)|0) + ')', type); } } - return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep); + return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type) + ']=' + value }).join(sep); } function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) { @@ -1483,10 +1296,6 @@ function makeStructuralReturn(values, inAsm) { }).concat([values[0]]).join(','), 'i32'); } -function makeStructuralAccess(ident, i) { - return ident + '$' + i; -} - function makeThrow(what) { return 'throw ' + what + (DISABLE_EXCEPTION_CATCHING == 1 ? ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch."' : '') + ';'; } @@ -1500,17 +1309,17 @@ function makeSignOp(value, type, op, force, ignore) { var bits, full; if (type[0] === 'i') { bits = parseInt(type.substr(1)); - full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore || correctSpecificSign()) + ')'; + full = op + 'Sign(' + value + ', ' + bits + ', ' + Math.floor(ignore) + ')'; // Always sign/unsign constants at compile time, regardless of CHECK/CORRECT if (isNumber(value)) { return eval(full).toString(); } } - if ((ignore || !correctSigns()) && !CHECK_SIGNS && !force) return value; + if ((ignore) && !force) return value; if (type[0] === 'i') { // this is an integer, but not a number (or we would have already handled it) // shortcuts - if (!CHECK_SIGNS || ignore) { + if (ignore) { if (value === 'true') { value = '1'; } else if (value === 'false') { diff --git a/src/preamble.js b/src/preamble.js index 030f99cc5f5f8..98ba92916d412 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -93,35 +93,6 @@ function CHECK_ALIGN_2(addr) { #endif -#if CHECK_OVERFLOWS -//======================================== -// Debugging tools - Mathop overflows -//======================================== -function CHECK_OVERFLOW(value, bits, ignore, sig) { - if (ignore) return value; - var twopbits = Math.pow(2, bits); - var twopbits1 = Math.pow(2, bits-1); - // For signedness issue here, see settings.js, CHECK_SIGNED_OVERFLOWS -#if CHECK_SIGNED_OVERFLOWS - if (value === Infinity || value === -Infinity || value >= twopbits1 || value < -twopbits1) { - throw 'SignedOverflow'; - if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) throw 'Overflow'; - } -#else - if (value === Infinity || value === -Infinity || Math.abs(value) >= twopbits) { - throw 'Overflow'; - } -#endif -#if CORRECT_OVERFLOWS - // Fail on >32 bits - we warned at compile time - if (bits <= 32) { - value = value & (twopbits - 1); - } -#endif - return value; -} -#endif - #if LABEL_DEBUG //======================================== // Debugging tools - Code flow progress @@ -1360,7 +1331,6 @@ Module['writeAsciiToMemory'] = writeAsciiToMemory; {{{ unSign }}} {{{ reSign }}} -#if PRECISE_I32_MUL // check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 ) if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) { var ah = a >>> 16; @@ -1369,11 +1339,6 @@ if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function var bl = b & 0xffff; return (al*bl + ((ah*bl + al*bh) << 16))|0; }; -#else -Math['imul'] = function imul(a, b) { - return (a*b)|0; // fast but imprecise -}; -#endif Math.imul = Math['imul']; #if PRECISE_F32 diff --git a/src/runtime.js b/src/runtime.js index dd757fd57c23d..a66fa5a159148 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -61,7 +61,7 @@ var RuntimeGenerator = { dynamicAlloc: function(size) { if (ASSERTIONS) size = '(assert(DYNAMICTOP > 0),' + size + ')'; // dynamic area must be ready var ret = RuntimeGenerator.alloc(size, 'DYNAMIC', INIT_HEAP); - ret += '; if (DYNAMICTOP >= TOTAL_MEMORY) { var success = enlargeMemory(); if (!success) return 0; }' + ret += '; if (DYNAMICTOP >= TOTAL_MEMORY) { var success = enlargeMemory(); if (!success) { DYNAMICTOP = ret; return 0; } }' return ret; }, @@ -414,9 +414,6 @@ function unSign(value, bits, ignore) { if (value >= 0) { return value; } -#if CHECK_SIGNS - if (!ignore) throw 'UnSign'; -#endif return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts : Math.pow(2, bits) + value; } @@ -429,25 +426,11 @@ function reSign(value, bits, ignore) { } var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32 : Math.pow(2, bits-1); -#if CHECK_SIGNS - var noted = false; -#endif if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don't do that // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors // TODO: In i64 mode 1, resign the two parts separately and safely -#if CHECK_SIGNS - if (!ignore) throw 'ReSign'; -#endif value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts } -#if CHECK_SIGNS - // If this is a 32-bit value, then it should be corrected at this point. And, - // without CHECK_SIGNS, we would just do the |0 shortcut, so check that that - // would indeed give the exact same result. - if (bits === 32 && (value|0) !== value && typeof value !== 'boolean') { - if (!ignore) throw 'ReSign'; - } -#endif return value; } diff --git a/src/settings.js b/src/settings.js index 778a9c7bce63a..f3c5b6f166d0f 100644 --- a/src/settings.js +++ b/src/settings.js @@ -25,17 +25,6 @@ var QUANTUM_SIZE = 4; // This is the size of an individual field in a structure. var TARGET_ASMJS_UNKNOWN_EMSCRIPTEN = 1; // For asmjs-unknown-emscripten. 1 is normal, 2 is for the fastcomp llvm // backend using emscripten-customized abi simplification -var CORRECT_SIGNS = 1; // Whether we make sure to convert unsigned values to signed values. - // Decreases performance with additional runtime checks. Might not be - // needed in some kinds of code. - // If equal to 2, done on a line-by-line basis according to - // CORRECT_SIGNS_LINES, correcting only the specified lines. - // If equal to 3, correcting all *but* the specified lines -var CHECK_SIGNS = 0; // Runtime errors for signing issues that need correcting. - // It is recommended to use this in - // order to find if your code needs CORRECT_SIGNS. If you can get your - // code to run without CORRECT_SIGNS, it will run much faster - var ASSERTIONS = 1; // Whether we should add runtime assertions, for example to // check that each allocation to the stack does not // exceed its size, whether all allocations (stack and static) are @@ -100,16 +89,10 @@ var WARN_UNALIGNED = 0; // Warn at compile time about instructions that LLVM tel // alignment. (this option is fastcomp-only) var PRECISE_I64_MATH = 1; // If enabled, i64 addition etc. is emulated - which is slow but precise. If disabled, // we use the 'double trick' which is fast but incurs rounding at high values. - // 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 = 1; // If enabled, i32 multiplication is done with full precision, which means it is - // correct even if the value exceeds the JS double-integer limit of ~52 bits (otherwise, - // rounding will occur above that range). var PRECISE_F32 = 0; // 0: Use JS numbers for floating-point values. These are 64-bit and do not model C++ // floats exactly, which are 32-bit. // 1: Model C++ floats precisely, using Math.fround, polyfilling when necessary. This @@ -308,34 +291,6 @@ var ASYNCIFY_WHITELIST = ['qsort', // Functions in this list are never conside var EXECUTION_TIMEOUT = -1; // Throw an exception after X seconds - useful to debug infinite loops -var CHECK_OVERFLOWS = 0; // Add code that checks for overflows in integer math operations. - // There is currently not much to do to handle overflows if they occur. - // We can add code to simulate i32/i64 overflows in JS, but that would - // be very slow. It probably makes more sense to avoid overflows in - // C/C++ code. For example, if you have an int that you multiply by - // some factor, in order to get 'random' hash values - by taking - // that |value & hash_table_size| - then multiplying enough times will overflow. - // But instead, you can do |value = value & 30_BITS| in each iteration. -var CHECK_SIGNED_OVERFLOWS = 0; // Whether to allow *signed* overflows - our correction for overflows generates signed - // values (since we use &). This means that we correct some things are not strictly overflows, - // and we cause them to be signed (which may lead to unnecessary unSign()ing later). - // With this enabled, we check signed overflows for CHECK_OVERFLOWS -var CORRECT_OVERFLOWS = 1; // Experimental code that tries to prevent unexpected JS overflows in integer - // mathops, by doing controlled overflows (sort of parallel to a CPU). - // Note that as mentioned above in CHECK_OVERFLOWS, the best thing is to - // not rely on overflows in your C/C++ code, as even if this option works, - // it slows things down. - // - // If equal to 2, done on a line-by-line basis according to - // CORRECT_OVERFLOWS_LINES, correcting only the specified lines. - // If equal to 3, correcting all *but* the specified lines - // - // NOTE: You can introduce signing issues by using this option. If you - // take a large enough 32-bit value, and correct it for overflows, - // you may get a negative number, as JS & operations are signed. -var CORRECT_ROUNDINGS = 1; // C rounds to 0 (-5.5 to -5, +5.5 to 5), while JS has no direct way to do that: - // Math.floor is to negative, ceil to positive. With CORRECT_ROUNDINGS, - // we will do slow but correct C rounding operations. var FS_LOG = 0; // Log all FS operations. This is especially helpful when you're porting // a new project and want to see a list of file system operations happening // so that you can create a virtual file system with all of the required files. @@ -610,9 +565,6 @@ var DEBUG_TAGS_SHOWING = []; // For internal use only var ORIGINAL_EXPORTED_FUNCTIONS = []; -var CORRECT_OVERFLOWS_LINES = []; -var CORRECT_SIGNS_LINES = []; -var CORRECT_ROUNDINGS_LINES = []; var SAFE_HEAP_LINES = []; // The list of defines (C_DEFINES) was moved into struct_info.json in the same directory. diff --git a/src/utility.js b/src/utility.js index 54cc2d698f182..741367831722e 100644 --- a/src/utility.js +++ b/src/utility.js @@ -215,7 +215,7 @@ function concatenator(x, y) { } function mergeInto(obj, other) { - for (i in other) { + for (var i in other) { obj[i] = other[i]; } return obj; @@ -286,7 +286,7 @@ function numberedSet() { function setSub(x, y) { var ret = set(keys(x)); - for (yy in y) { + for (var yy in y) { if (yy in ret) { delete ret[yy]; } @@ -297,7 +297,7 @@ function setSub(x, y) { // Intersection of 2 sets. Faster if |xx| << |yy| function setIntersect(x, y) { var ret = {}; - for (xx in x) { + for (var xx in x) { if (xx in y) { ret[xx] = 0; } @@ -307,7 +307,7 @@ function setIntersect(x, y) { function setUnion(x, y) { var ret = set(keys(x)); - for (yy in y) { + for (var yy in y) { ret[yy] = 0; } return ret; diff --git a/tests/core/test_i32_mul_semiprecise.in b/tests/core/test_i32_mul_semiprecise.in deleted file mode 100644 index a93a69da34cf8..0000000000000 --- a/tests/core/test_i32_mul_semiprecise.in +++ /dev/null @@ -1,26 +0,0 @@ -#include - -typedef unsigned int uint; - -// from cube2, zlib licensed - -#define N (624) -#define M (397) -#define K (0x9908B0DFU) - -static uint state[N]; -static int next = N; - -void seedMT(uint seed) { - state[0] = seed; - for (uint i = 1; i < N; i++) // if we do not do this precisely, at least we - // should coerce to int immediately, not wait - state[i] = seed = 1812433253U * (seed ^ (seed >> 30)) + i; - next = 0; -} - -int main() { - seedMT(5497); - for (int i = 0; i < 10; i++) printf("%d: %u\n", i, state[i]); - return 0; -} diff --git a/tests/core/test_i32_mul_semiprecise.out b/tests/core/test_i32_mul_semiprecise.out deleted file mode 100644 index 261bf9a9fb9aa..0000000000000 --- a/tests/core/test_i32_mul_semiprecise.out +++ /dev/null @@ -1,10 +0,0 @@ -0: 5497 -1: 2916432318 -2: 2502517762 -3: 3151524867 -4: 2323729668 -5: 2053478917 -6: 2409490438 -7: 848473607 -8: 691103752 -9: 3915535113 diff --git a/tests/fuzz/creduce_tester.py b/tests/fuzz/creduce_tester.py index 6bf9473f4b5b9..7fd307791d557 100755 --- a/tests/fuzz/creduce_tester.py +++ b/tests/fuzz/creduce_tester.py @@ -14,8 +14,7 @@ # configuration options will have to be hardcoded. CSMITH_CFLAGS = ['-I', os.path.join(os.environ['CSMITH_PATH'], 'runtime')] ENGINE = shared.JS_ENGINES[0] -EMCC_ARGS = ['-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1', '-s', - 'PRECISE_I32_MUL=1'] +EMCC_ARGS = ['-O2', '-s', 'ASM_JS=1', '-s', 'PRECISE_I64_MATH=1'] filename = sys.argv[1] obj_filename = os.path.splitext(filename)[0] diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 8ae3d23b4eabc..a15ff7272f759 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -507,7 +507,7 @@ def test_corrections(self): return 0; } ''' - self.do_benchmark('corrections', src, 'final:', emcc_args=['-s', 'CORRECT_SIGNS=1', '-s', 'CORRECT_OVERFLOWS=1', '-s', 'CORRECT_ROUNDINGS=1']) + self.do_benchmark('corrections', src, 'final:') def fasta(self, name, double_rep, emcc_args=[]): src = open(path_from_root('tests', 'fasta.cpp'), 'r').read().replace('double', double_rep) diff --git a/tests/test_browser.py b/tests/test_browser.py index f6a426bc3a7ca..ad2383aa8f482 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1967,7 +1967,7 @@ def test_emrun_info(self): assert 'Traceback' not in result def test_emrun(self): - Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_exit.c'), '--emrun', '-o', 'hello_world.html']).communicate() + Popen([PYTHON, EMCC, path_from_root('tests', 'test_emrun.c'), '--emrun', '-o', 'hello_world.html']).communicate() outdir = os.getcwd() # We cannot run emrun from the temp directory the suite will clean up afterwards, since the browser that is launched will have that directory as startup directory, # and the browser will not close as part of the test, pinning down the cwd on Windows and it wouldn't be possible to delete it. Therefore switch away from that directory @@ -1985,6 +1985,8 @@ def test_emrun(self): assert 'argc: 4' in stdout assert 'argv[3]: --3' in stdout assert 'hello, world!' in stdout + assert 'Testing ASCII characters: !"$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' in stdout + assert 'Testing char sequences: %20%21 ä' in stdout assert 'hello, error stream!' in stderr def test_uuid(self): diff --git a/tests/test_core.py b/tests/test_core.py index 0cf310720238b..024acc76e8492 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -30,9 +30,6 @@ def test_intvars(self): self.do_run_from_file(src, output) def test_sintvars(self): - Settings.CORRECT_SIGNS = 1 # Relevant to this test - Settings.CORRECT_OVERFLOWS = 0 # We should not need overflow correction to get this right - test_path = path_from_root('tests', 'core', 'test_sintvars') src, output = (test_path + s for s in ('.in', '.out')) @@ -240,8 +237,6 @@ def test_i64(self): # stuff that also needs sign corrections - Settings.CORRECT_SIGNS = 1 - src = r''' #include #include @@ -425,19 +420,7 @@ def test_i32_mul_precise(self): self.do_run_from_file(src, output) - def test_i32_mul_semiprecise(self): - if Settings.ASM_JS: return self.skip('asm is always fully precise') - - Settings.PRECISE_I32_MUL = 0 # we want semiprecise here - - test_path = path_from_root('tests', 'core', 'test_i32_mul_semiprecise') - src, output = (test_path + s for s in ('.in', '.out')) - - self.do_run_from_file(src, output) - def test_i16_emcc_intrinsic(self): - Settings.CORRECT_SIGNS = 1 # Relevant to this test - test_path = path_from_root('tests', 'core', 'test_i16_emcc_intrinsic') src, output = (test_path + s for s in ('.in', '.out')) @@ -651,8 +634,6 @@ def test_align64(self): ''') def test_unsigned(self): - Settings.CORRECT_SIGNS = 1 # We test for exactly this sort of thing here - Settings.CHECK_SIGNS = 0 src = ''' #include const signed char cvals[2] = { -1, -2 }; // compiler can store this is a string, so -1 becomes \FF, and needs re-signing @@ -691,9 +672,6 @@ def test_unsigned(self): ''' self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*') - Settings.CHECK_SIGNS = 0 - Settings.CORRECT_SIGNS = 0 - src = ''' #include int main() @@ -2151,6 +2129,26 @@ def test_inlinejs3(self): src = open(src).read().replace('emscripten_debugger();', '') self.do_run(src, open(output).read()) + def test_inlinejs4(self): + self.do_run(r''' +#include + +#define TO_STRING_INNER(x) #x +#define TO_STRING(x) TO_STRING_INNER(x) +#define assert_msg(msg, file, line) EM_ASM( throw 'Assert (' + msg + ') failed in ' + file + ':' + line + '!'; ) +#define assert(expr) { \ + if (!(expr)) { \ + assert_msg(#expr, TO_STRING(__FILE__), TO_STRING(__LINE__)); \ + } \ +} + +int main(int argc, char **argv) { + assert(argc != 17); + assert(false); + return 0; +} +''', 'false') + def test_em_asm_unicode(self): self.do_run(r''' #include @@ -2258,8 +2256,6 @@ def test_tinyfuncstr(self): self.do_run_from_file(src, output) def test_llvmswitch(self): - Settings.CORRECT_SIGNS = 1 - test_path = path_from_root('tests', 'core', 'test_llvmswitch') src, output = (test_path + s for s in ('.in', '.out')) @@ -3082,8 +3078,6 @@ class Bar { def test_dlfcn_qsort(self): if not self.can_dlfcn(): return - Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations - self.prep_dlfcn_lib() Settings.EXPORTED_FUNCTIONS = ['_get_cmp'] lib_src = ''' @@ -4123,7 +4117,6 @@ def test_files(self): self.emcc_args = filter(lambda x: x != '-g', self.emcc_args) # ensure we test --closure 1 --memory-init-file 1 (-g would disable closure) self.emcc_args += ["-s", "CHECK_HEAP_ALIGN=0"] # disable heap align check here, it mixes poorly with closure - Settings.CORRECT_SIGNS = 1 # Just so our output is what we expect. Can flip them both. post = ''' def process(filename): src = \'\'\' @@ -4162,8 +4155,6 @@ def process(filename): def test_files_m(self): # Test for Module.stdin etc. - Settings.CORRECT_SIGNS = 1 - post = ''' def process(filename): src = \'\'\' @@ -4713,8 +4704,6 @@ def test_799(self): ''') def test_ctype(self): - # The bit fiddling done by the macros using __ctype_b_loc requires this. - Settings.CORRECT_SIGNS = 1 src = open(path_from_root('tests', 'ctype', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read() self.do_run(src, expected) @@ -4976,7 +4965,6 @@ def test_whets(self): def test_dlmalloc(self): self.banned_js_engines = [NODE_JS] # slower, and fail on 64-bit - Settings.CORRECT_SIGNS = 1 Settings.TOTAL_MEMORY = 128*1024*1024 # needed with typed arrays src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() @@ -5087,12 +5075,6 @@ def test_cubescript(self): Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default - # Overflows happen in hash loop - Settings.CORRECT_OVERFLOWS = 1 - Settings.CHECK_OVERFLOWS = 0 - - Settings.CORRECT_SIGNS = 1 - def test(): self.do_run(path_from_root('tests', 'cubescript'), '*\nTemp is 33\n9\n5\nhello, everyone\n*', main_file='command.cpp') @@ -5245,8 +5227,6 @@ def test_freetype(self): if self.run_name == 'asm2g': Settings.ALIASING_FUNCTION_POINTERS = 1 - Settings.ALIASING_FUNCTION_POINTERS # flip for some more coverage here - if Settings.CORRECT_SIGNS == 0: Settings.CORRECT_SIGNS = 1 # Not sure why, but needed - post = ''' def process(filename): import tools.shared as shared @@ -5305,9 +5285,6 @@ def test_sqlite(self): if '-O' not in str(self.emcc_args): self.banned_js_engines += [SPIDERMONKEY_ENGINE] # SM bug 1066759 - Settings.CORRECT_SIGNS = 1 - Settings.CORRECT_OVERFLOWS = 0 - Settings.CORRECT_ROUNDINGS = 0 Settings.DISABLE_EXCEPTION_CATCHING = 1 Settings.EXPORTED_FUNCTIONS += ['_sqlite3_open', '_sqlite3_close', '_sqlite3_exec', '_sqlite3_free', '_callback']; if Settings.ASM_JS == 1 and '-g' in self.emcc_args: @@ -5335,8 +5312,6 @@ def test_zlib(self): if self.run_name == 'asm2g': self.emcc_args += ['-g4'] # more source maps coverage - Settings.CORRECT_SIGNS = 1 - use_cmake_configure = WINDOWS if use_cmake_configure: make_args = [] @@ -5395,8 +5370,6 @@ def test(): assert old.count('tempBigInt') > new.count('tempBigInt') def test_poppler(self): - Settings.CORRECT_OVERFLOWS = 1 - Settings.CORRECT_SIGNS = 1 Settings.NO_EXIT_RUNTIME = 1 Building.COMPILER_TEST_OPTS += [ @@ -5451,8 +5424,6 @@ def process(filename): def test_openjpeg(self): Building.COMPILER_TEST_OPTS = filter(lambda x: x != '-g', Building.COMPILER_TEST_OPTS) # remove -g, so we have one test without it by default - Settings.CORRECT_SIGNS = 1 - post = ''' def process(filename): import tools.shared as shared @@ -5619,8 +5590,6 @@ def test_cases(self): need_no_leave_inputs_raw = ['muli33_ta2', 'philoop_ta2'] try: - Settings.CHECK_OVERFLOWS = 0 - for name in glob.glob(path_from_root('tests', 'cases', '*.ll')): shortname = name.replace('.ll', '') if '' not in shortname: continue @@ -6759,144 +6728,6 @@ def test_emscripten_log(self): if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g') self.do_run('#define RUN_FROM_JS_SHELL\n' + open(path_from_root('tests', 'emscripten_log', 'emscripten_log.cpp')).read(), "Success!") - def test_linespecific(self): - if Settings.ASM_JS: return self.skip('asm always has corrections on') - - if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g') - if self.emcc_args: - self.emcc_args += ['--llvm-opts', '0'] # llvm full opts make the expected failures here not happen - Building.COMPILER_TEST_OPTS += ['--llvm-opts', '0'] - - Settings.CHECK_SIGNS = 0 - Settings.CHECK_OVERFLOWS = 0 - - # Signs - - src = ''' - #include - #include - - int main() - { - int varey = 100; - unsigned int MAXEY = -1; - printf("*%d*\\n", varey >= MAXEY); // 100 >= -1? not in unsigned! - } - ''' - - Settings.CORRECT_SIGNS = 0 - self.do_run(src, '*1*') # This is a fail - we expect 0 - - Settings.CORRECT_SIGNS = 1 - self.do_run(src, '*0*') # Now it will work properly - - ## And now let's fix just that one line - #Settings.CORRECT_SIGNS = 2 - #Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"] - #self.do_run(src, '*0*') - - # Fixing the wrong line should not work - Settings.CORRECT_SIGNS = 2 - Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"] - self.do_run(src, '*1*') - - # And reverse the checks with = 2 - Settings.CORRECT_SIGNS = 3 - Settings.CORRECT_SIGNS_LINES = ["src.cpp:3"] - self.do_run(src, '*0*') - Settings.CORRECT_SIGNS = 3 - Settings.CORRECT_SIGNS_LINES = ["src.cpp:9"] - self.do_run(src, '*1*') - - Settings.CORRECT_SIGNS = 0 - - # Overflows - - src = ''' - #include - int main() { - int t = 77; - for (int i = 0; i < 30; i++) { - t = t + t + t + t + t + 1; - } - printf("*%d,%d*\\n", t, t & 127); - return 0; - } - ''' - - correct = '*186854335,63*' - Settings.CORRECT_OVERFLOWS = 0 - try: - self.do_run(src, correct) - raise Exception('UNEXPECTED-PASS') - except Exception, e: - assert 'UNEXPECTED' not in str(e), str(e) - assert 'Expected to find' in str(e), str(e) - - Settings.CORRECT_OVERFLOWS = 1 - self.do_run(src, correct) # Now it will work properly - - # And now let's fix just that one line - Settings.CORRECT_OVERFLOWS = 2 - Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"] - self.do_run(src, correct) - - # Fixing the wrong line should not work - Settings.CORRECT_OVERFLOWS = 2 - Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"] - try: - self.do_run(src, correct) - raise Exception('UNEXPECTED-PASS') - except Exception, e: - assert 'UNEXPECTED' not in str(e), str(e) - assert 'Expected to find' in str(e), str(e) - - # And reverse the checks with = 2 - Settings.CORRECT_OVERFLOWS = 3 - Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:3"] - self.do_run(src, correct) - Settings.CORRECT_OVERFLOWS = 3 - Settings.CORRECT_OVERFLOWS_LINES = ["src.cpp:6"] - try: - self.do_run(src, correct) - raise Exception('UNEXPECTED-PASS') - except Exception, e: - assert 'UNEXPECTED' not in str(e), str(e) - assert 'Expected to find' in str(e), str(e) - - Settings.CORRECT_OVERFLOWS = 0 - - # Roundings - - src = ''' - #include - #include - - int main() - { - TYPE x = -5; - printf("*%d*", x/2); - x = 5; - printf("*%d*", x/2); - - float y = -5.33; - x = y; - printf("*%d*", x); - y = 5.33; - x = y; - printf("*%d*", x); - - printf("\\n"); - } - ''' - - Settings.CORRECT_ROUNDINGS = 1 - Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well - self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct - self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct - self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct - Settings.CORRECT_SIGNS = 0 - def test_float_literals(self): self.do_run_from_file(path_from_root('tests', 'test_float_literals.cpp'), path_from_root('tests', 'test_float_literals.out')) diff --git a/tests/test_emrun.c b/tests/test_emrun.c new file mode 100644 index 0000000000000..453e7ce493e40 --- /dev/null +++ b/tests/test_emrun.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int main(int argc, char **argv) { + printf("argc: %d\n", argc); + for(int i = 0; i < argc; ++i) { + printf("argv[%d]: %s\n", i, argv[i]); + } + + // Dump a file to local filesystem with emrun. + EM_ASM(emrun_file_dump("test.dat", HEAPU8.subarray(0, 128));); + EM_ASM(emrun_file_dump("heap.dat", HEAPU8)); + + if (argc <= 1) + exit(1); + printf("hello, world!\n"); + fprintf(stderr, "hello, error stream!\n"); + + printf("Testing ASCII characters: !\"$%%&'()*+,-./:;<=>?@[\\]^_`{|}~\n"); + printf("Testing char sequences: %%20%%21 ä\n"); + + exit(100); +} + diff --git a/tests/test_other.py b/tests/test_other.py index 44b56d7bbce35..f9ff1f22c19fd 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -4946,11 +4946,14 @@ def test_massive_alloc(self): self.assertContained('''Warning: Enlarging memory arrays, this is not fast! 16777216,1543503872\n''', output) def test_failing_alloc(self): - open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' + for pre_fail, post_fail in [('', ''), ('EM_ASM( Module.temp = DYNAMICTOP );', 'EM_ASM( assert(Module.temp === DYNAMICTOP, "must not adjust DYNAMICTOP when an alloc fails!") );')]: + print 'test opts:', pre_fail, post_fail, '.' + open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r''' #include #include #include #include +#include #define CHUNK_SIZE (10*1024*1024) @@ -4959,10 +4962,14 @@ def test_failing_alloc(self): bool has = false; while (1) { printf("trying an allocation\n"); + %s void* curr = malloc(CHUNK_SIZE); - if (!curr) break; + if (!curr) { + %s + break; + } has = true; - printf("allocated another chunk, %d so far\n", allocs.size()); + printf("allocated another chunk, %%d so far\n", allocs.size()); allocs.push_back(curr); } assert(has); @@ -4976,12 +4983,12 @@ def test_failing_alloc(self): } printf("managed another malloc!\n"); } - ''') - Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'ALLOW_MEMORY_GROWTH=1']).communicate()[1] - assert os.path.exists('a.out.js') - output = run_js('a.out.js', stderr=PIPE, full_output=True, assert_returncode=None) - # just care about message regarding allocating over 1GB of memory - self.assertContained('''managed another malloc!\n''', output) + ''' % (pre_fail, post_fail)) + Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'ALLOW_MEMORY_GROWTH=1']).communicate()[1] + assert os.path.exists('a.out.js') + output = run_js('a.out.js', stderr=PIPE, full_output=True, assert_returncode=None) + # just care about message regarding allocating over 1GB of memory + self.assertContained('''managed another malloc!\n''', output) def test_libcxx_minimal(self): open('vector.cpp', 'w').write(r''' diff --git a/tools/system_libs.py b/tools/system_libs.py index 79f5a91827a76..937e6772f6632 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -271,15 +271,6 @@ def create_libc(): return build_libc('libc.bc', libc_files, ['-O2']) def apply_libc(need): - # libc needs some sign correction. # If we are in mode 0, switch to 2. We will add our lines - try: - if shared.Settings.CORRECT_SIGNS == 0: raise Exception('we need to change to 2') - except: # we fail if equal to 0 - so we need to switch to 2 - or if CORRECT_SIGNS is not even in Settings - shared.Settings.CORRECT_SIGNS = 2 - if shared.Settings.CORRECT_SIGNS == 2: - shared.Settings.CORRECT_SIGNS_LINES = [shared.path_from_root('src', 'dlmalloc.c') + ':' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] - # If we are in mode 1, we are correcting everything anyhow. If we are in mode 3, we will be corrected - # so all is well anyhow too. return True # libcextra @@ -624,8 +615,6 @@ def create_libcxx(): def apply_libcxx(need): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++ with QUANTUM_SIZE == 1' - # libcxx might need corrections, so turn them all on. TODO: check which are actually needed - shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 #logging.info('using libcxx turns on CORRECT_* options') return True @@ -650,8 +639,6 @@ def create_libcxxabi(): def apply_libcxxabi(need): assert shared.Settings.QUANTUM_SIZE == 4, 'We do not support libc++abi with QUANTUM_SIZE == 1' - #logging.info('using libcxxabi, this may need CORRECT_* options') - #shared.Settings.CORRECT_SIGNS = shared.Settings.CORRECT_OVERFLOWS = shared.Settings.CORRECT_ROUNDINGS = 1 return True # gl