diff options
38 files changed, 2154 insertions, 573 deletions
@@ -215,6 +215,20 @@ Options that are modified or new in %s include: (without the external "s in either of those, you would get an error) + You can also specify a file from which the + value would be read, for example, + + -s DEAD_FUNCTIONS=@/path/to/file + + The contents of /path/to/file will be read, + JSON.parsed and set into DEAD_FUNCTIONS (so + the file could contain + + ["_func1", "func2"] + + ). Note that the path must be absolute, not + relative. + -g Use debug info. Note that you need this during the last compilation phase from bitcode to JavaScript, or else we will remove it by @@ -973,6 +987,8 @@ try: # Apply -s settings in newargs here (after optimization levels, so they can override them) for change in settings_changes: key, value = change.split('=') + if value[0] == '@': + value = '"' + value + '"' exec('shared.Settings.' + key + ' = ' + value) # Apply effects from settings diff --git a/emscripten.py b/emscripten.py index bbc4f76d..c9d8505d 100755 --- a/emscripten.py +++ b/emscripten.py @@ -34,9 +34,13 @@ MIN_CHUNK_SIZE = 1024*1024 MAX_CHUNK_SIZE = float(os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or 'inf') # configuring this is just for debugging purposes def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, temp_files, DEBUG)): - ll = ''.join(funcs) + '\n' + meta funcs_file = temp_files.get('.func_%d.ll' % i).name - open(funcs_file, 'w').write(ll) + f = open(funcs_file, 'w') + f.write(funcs) + funcs = None + f.write('\n') + f.write(meta) + f.close() out = jsrun.run_js( compiler, engine=compiler_engine, @@ -188,6 +192,8 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, funcs, chunk_size, jcache.get_cachename('emscript_files') if jcache else None) + funcs = None + if jcache: # load chunks from cache where we can # TODO: ignore small chunks cached_outputs = [] @@ -223,6 +229,9 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, outputs = pool.map(process_funcs, commands, chunksize=1) elif len(chunks) == 1: outputs = [process_funcs(commands[0])] + + commands = None + else: outputs = [] @@ -235,6 +244,8 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, jcache.set(shortkey, keys, outputs[i]) if out and DEBUG and len(chunks) > 0: print >> sys.stderr, ' saving %d funcchunks to jcache' % len(chunks) + chunks = None + if jcache: outputs += cached_outputs # TODO: preserve order outputs = [output.split('//FORWARDED_DATA:') for output in outputs] @@ -258,8 +269,10 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, for key in curr_forwarded_json['Functions']['indexedFunctions'].iterkeys(): indexed_functions.add(key) if settings.get('ASM_JS'): + export_bindings = settings['EXPORT_BINDINGS'] for key in curr_forwarded_json['Functions']['implementedFunctions'].iterkeys(): - if key in all_exported_functions: exported_implemented_functions.add(key) + if key in all_exported_functions or (export_bindings and key.startswith('_emscripten_bind')): + exported_implemented_functions.add(key) for key, value in curr_forwarded_json['Functions']['unimplementedFunctions'].iteritems(): forwarded_json['Functions']['unimplementedFunctions'][key] = value @@ -268,7 +281,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if len(parts) > 1: pre = parts[0] outputs.append([parts[1]]) - funcs_js = ''.join([output[0] for output in outputs]) + funcs_js = [''.join([output[0] for output in outputs])] # this will be a list of things, so we do not do string appending as we add more outputs = None if DEBUG: print >> sys.stderr, ' emscript: phase 2b took %s seconds' % (time.time() - t) @@ -313,6 +326,10 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, last_forwarded_json = json.loads(last_forwarded_data) if settings.get('ASM_JS'): + post_funcs, post_rest = post.split('// EMSCRIPTEN_END_FUNCS\n') + post = post_rest + funcs_js += ['\n' + post_funcs + '// EMSCRIPTEN_END_FUNCS\n'] + simple = os.environ.get('EMCC_SIMPLE_ASM') class Counter: i = 0 @@ -320,11 +337,12 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, del last_forwarded_json['Functions']['tables']['pre'] # Find function table calls without function tables generated for them - for use in set(re.findall(r'{{{ FTM_[\w\d_$]+ }}}', funcs_js)): - sig = use[8:len(use)-4] - if sig not in last_forwarded_json['Functions']['tables']: - if DEBUG: print >> sys.stderr, 'add empty function table', sig - last_forwarded_json['Functions']['tables'][sig] = 'var FUNCTION_TABLE_' + sig + ' = [0,0];\n' + for funcs_js_item in funcs_js: + for use in set(re.findall(r'{{{ FTM_[\w\d_$]+ }}}', funcs_js_item)): + sig = use[8:len(use)-4] + if sig not in last_forwarded_json['Functions']['tables']: + if DEBUG: print >> sys.stderr, 'add empty function table', sig + last_forwarded_json['Functions']['tables'][sig] = 'var FUNCTION_TABLE_' + sig + ' = [0,0];\n' def make_table(sig, raw): i = Counter.i @@ -340,7 +358,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, asm_setup = '' maths = ['Math.' + func for func in ['floor', 'abs', 'sqrt', 'pow', 'cos', 'sin', 'tan', 'acos', 'asin', 'atan', 'atan2', 'exp', 'log', 'ceil', 'imul']] fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] - math_envs = ['Runtime.bitshift64', 'Math.min'] # TODO: move min to maths + math_envs = ['Math.min'] # TODO: move min to maths asm_setup += '\n'.join(['var %s = %s;' % (f.replace('.', '_'), f) for f in math_envs]) basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat', 'copyTempDouble', 'copyTempFloat'] + [m.replace('.', '_') for m in math_envs] if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_HEAP_CLEAR'] @@ -411,9 +429,9 @@ var i64Math_modulo = function(a, b, c, d, e) { i64Math.modulo(a, b, c, d, e) }; # finalize - if DEBUG: print >> sys.stderr, 'asm text sizes', len(funcs_js), len(asm_setup), len(asm_global_vars), len(asm_global_funcs), len(pre_tables), len('\n'.join(function_tables_impls)), len(function_tables_defs.replace('\n', '\n ')), len(exports), len(the_global), len(sending), len(receiving) + if DEBUG: print >> sys.stderr, 'asm text sizes', map(len, funcs_js), len(asm_setup), len(asm_global_vars), len(asm_global_funcs), len(pre_tables), len('\n'.join(function_tables_impls)), len(function_tables_defs.replace('\n', '\n ')), len(exports), len(the_global), len(sending), len(receiving) - funcs_js = ''' + funcs_js = [''' %s function asmPrintInt(x, y) { Module.print('int ' + x + ',' + y);// + ' ' + new Error().stack); @@ -463,7 +481,7 @@ var asm = (function(global, env, buffer) { value = value|0; tempRet%d = value; } -''' % (i, i) for i in range(10)]) + funcs_js + ''' +''' % (i, i) for i in range(10)])] + funcs_js + [''' %s return %s; @@ -474,7 +492,7 @@ var asm = (function(global, env, buffer) { Runtime.stackAlloc = function(size) { return asm.stackAlloc(size) }; Runtime.stackSave = function() { return asm.stackSave() }; Runtime.stackRestore = function(top) { asm.stackRestore(top) }; -''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, the_global, sending, receiving) +''' % (pre_tables + '\n'.join(function_tables_impls) + '\n' + function_tables_defs.replace('\n', '\n '), exports, the_global, sending, receiving)] # Set function table masks def function_table_maskize(js): @@ -487,17 +505,20 @@ Runtime.stackRestore = function(top) { asm.stackRestore(top) }; sig = m.groups(0)[0] return masks[sig] return re.sub(r'{{{ FTM_([\w\d_$]+) }}}', lambda m: fix(m), js) # masks[m.groups(0)[0]] - funcs_js = function_table_maskize(funcs_js) + funcs_js = map(function_table_maskize, funcs_js) else: function_tables_defs = '\n'.join([table for table in last_forwarded_json['Functions']['tables'].itervalues()]) outfile.write(function_tables_defs) - funcs_js = ''' + funcs_js = [''' // EMSCRIPTEN_START_FUNCS -''' + funcs_js + ''' +'''] + funcs_js + [''' // EMSCRIPTEN_END_FUNCS -''' +'''] - outfile.write(blockaddrsize(indexize(funcs_js))) + for funcs_js_item in funcs_js: # do this loop carefully to save memory + funcs_js_item = indexize(funcs_js_item) + funcs_js_item = blockaddrsize(funcs_js_item) + outfile.write(funcs_js_item) funcs_js = None outfile.write(indexize(post)) diff --git a/src/analyzer.js b/src/analyzer.js index 926ac9d3..92b7d8cf 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -18,7 +18,7 @@ function recomputeLines(func) { // Handy sets var BRANCH_INVOKE = set('branch', 'invoke'); -var LABEL_ENDERS = set('branch', 'return'); +var LABEL_ENDERS = set('branch', 'return', 'switch'); var SIDE_EFFECT_CAUSERS = set('call', 'invoke', 'atomic'); var UNUNFOLDABLE = set('value', 'structvalue', 'type', 'phiparam'); @@ -653,13 +653,14 @@ function analyzer(data, sidePass) { if (!isNumber(shifts)) { // We can't statically legalize this, do the operation at runtime TODO: optimize assert(sourceBits == 64, 'TODO: handle nonconstant shifts on != 64 bits'); + assert(PRECISE_I64_MATH, 'Must have precise i64 math for non-constant 64-bit shifts'); + Types.preciseI64MathUsed = 1; value.intertype = 'value'; - value.ident = 'Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + + value.ident = 'var ' + value.assignTo + '$0 = _bitshift64' + value.op[0].toUpperCase() + value.op.substr(1) + '(' + asmCoercion(sourceElements[0].ident, 'i32') + ',' + asmCoercion(sourceElements[1].ident, 'i32') + ',' + - Runtime['BITSHIFT64_' + value.op.toUpperCase()] + ',' + asmCoercion(value.params[1].ident + '$0', 'i32') + ');' + - 'var ' + value.assignTo + '$0 = ' + makeGetTempDouble(0, 'i32') + ', ' + value.assignTo + '$1 = ' + makeGetTempDouble(1, 'i32') + ';'; + 'var ' + value.assignTo + '$1 = tempRet0;'; value.assignTo = null; i++; continue; diff --git a/src/compiler.js b/src/compiler.js index 447d34b7..bb72c7dd 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -141,8 +141,13 @@ if (phase == 'pre') { if (settings_file) { var settings = JSON.parse(read(settings_file)); - for (setting in settings) { - eval(setting + ' = ' + JSON.stringify(settings[setting])); + for (key in settings) { + var value = settings[key]; + if (value[0] == '@') { + // response file type thing, workaround for large inputs: value is @path-to-file + value = JSON.parse(read(value.substr(1))); + } + eval(key + ' = ' + JSON.stringify(value)); } } @@ -163,7 +168,7 @@ if (SAFE_HEAP >= 2) { EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); EXCEPTION_CATCHING_WHITELIST = set(EXCEPTION_CATCHING_WHITELIST); -DEAD_FUNCTIONS = set(DEAD_FUNCTIONS); +DEAD_FUNCTIONS = numberedSet(DEAD_FUNCTIONS); RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG; diff --git a/src/headless.js b/src/headless.js index 8e847d27..d81fb5a3 100644 --- a/src/headless.js +++ b/src/headless.js @@ -537,7 +537,7 @@ var document = { case /* GL_MAX_FRAGMENT_UNIFORM_VECTORS */ 0x8DFD: return 4096; case /* GL_MAX_VARYING_VECTORS */ 0x8DFC: return 32; case /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS */ 0x8B4D: return 32; - default: throw 'getParameter ' + pname; + default: console.log('getParameter ' + pname + '?'); return 0; } }, getSupportedExtensions: function() { @@ -686,6 +686,7 @@ var document = { document.callEventListeners('pointerlockchange'); }); }, + exitPointerLock: function(){}, style: {}, eventListeners: {}, addEventListener: document.addEventListener, @@ -748,6 +749,8 @@ var document = { body: { appendChild: function(){}, }, + exitPointerLock: function(){}, + cancelFullScreen: function(){}, }; var alert = function(x) { print(x); diff --git a/src/jsifier.js b/src/jsifier.js index d36f26ce..7db2ee70 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -397,6 +397,20 @@ function JSify(data, functionsOnly, givenFunctions) { } }); + function processLibraryFunction(snippet, ident) { + snippet = snippet.toString(); + assert(snippet.indexOf('XXX missing C define') == -1, + 'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet); + + // name the function; overwrite if it's already named + snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); + if (LIBRARY_DEBUG) { + snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); + snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}'; + } + return snippet; + } + // functionStub substrate.addActor('FunctionStub', { processItem: function(item) { @@ -434,16 +448,7 @@ function JSify(data, functionsOnly, givenFunctions) { snippet = stringifyWithFunctions(snippet); } else if (typeof snippet === 'function') { isFunction = true; - snippet = snippet.toString(); - assert(snippet.indexOf('XXX missing C define') == -1, - 'Trying to include a library function with missing C defines: ' + ident + ' | ' + snippet); - - // name the function; overwrite if it's already named - snippet = snippet.replace(/function(?:\s+([^(]+))?\s*\(/, 'function _' + ident + '('); - if (LIBRARY_DEBUG) { - snippet = snippet.replace('{', '{ var ret = (function() { if (Runtime.debug) Module.printErr("[library call:' + ident + ': " + Array.prototype.slice.call(arguments).map(Runtime.prettyPrint) + "]"); '); - snippet = snippet.substr(0, snippet.length-1) + '}).apply(this, arguments); if (Runtime.debug && typeof ret !== "undefined") Module.printErr(" [ return:" + Runtime.prettyPrint(ret)); return ret; \n}'; - } + snippet = processLibraryFunction(snippet, ident); if (ASM_JS) Functions.libraryFunctions[ident] = 1; } @@ -507,9 +512,13 @@ function JSify(data, functionsOnly, givenFunctions) { } else if (LibraryManager.library.hasOwnProperty(shortident)) { item.JS = addFromLibrary(shortident); } else if (!LibraryManager.library.hasOwnProperty(shortident + '__inline')) { - item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; - if (WARN_ON_UNDEFINED_SYMBOLS || ASM_JS) { // always warn on undefs in asm, since it breaks validation - warn('Unresolved symbol: ' + item.ident); + if (!(item.ident in DEAD_FUNCTIONS) && !UNRESOLVED_AS_DEAD) { + item.JS = 'var ' + item.ident + '; // stub for ' + item.ident; + if (ASM_JS) { + throw 'Unresolved symbol: ' + item.ident + ', this must be corrected for asm.js validation to succeed. Consider adding it to DEAD_FUNCTIONS.'; + } else if (WARN_ON_UNDEFINED_SYMBOLS) { + warn('Unresolved symbol: ' + item.ident); + } } } return ret; @@ -717,6 +726,7 @@ function JSify(data, functionsOnly, givenFunctions) { ret += indent + 'label = ' + getLabelId(block.entries[0]) + '; ' + (SHOW_LABELS ? '/* ' + getOriginalLabelId(block.entries[0]) + ' */' : '') + '\n'; } // otherwise, should have been set before! if (func.setjmpTable) { + assert(!ASM_JS, 'asm.js mode does not support setjmp yet'); var setjmpTable = {}; ret += indent + 'var mySetjmpIds = {};\n'; ret += indent + 'var setjmpTable = {'; @@ -1316,6 +1326,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { callIdent = ident; } + if (callIdent == '0') return 'abort(-2)'; var args = []; var argsTypes = []; @@ -1420,7 +1431,7 @@ function JSify(data, functionsOnly, givenFunctions) { } if (callIdent in DEAD_FUNCTIONS) { - var ret = 'abort(7)'; + var ret = 'abort(' + DEAD_FUNCTIONS[callIdent] + ')'; if (ASM_JS) ret = asmCoercion(ret, returnType); return ret; } @@ -1563,16 +1574,25 @@ function JSify(data, functionsOnly, givenFunctions) { // This is the main 'post' pass. Print out the generated code that we have here, together with the // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). - if (CORRUPTION_CHECK) { - assert(!ASM_JS); // cannot monkeypatch asm! - print(processMacros(read('corruptionCheck.js'))); - } if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { + if (!INCLUDE_FULL_LIBRARY) { + ['i64Add', 'bitshift64Shl', 'bitshift64Lshr', 'bitshift64Ashr'].forEach(function(func) { + print(processLibraryFunction(LibraryManager.library[func], func)); // must be first to be close to generated code + Functions.implementedFunctions['_' + func] = LibraryManager.library[func + '__sig']; + }); + } + print('// EMSCRIPTEN_END_FUNCS\n'); print(read('long.js')); } else { + print('// EMSCRIPTEN_END_FUNCS\n'); print('// Warning: printing of i64 values may be slightly rounded! No deep i64 math used, so precise i64 code not included'); print('var i64Math = null;'); } + + if (CORRUPTION_CHECK) { + assert(!ASM_JS); // cannot monkeypatch asm! + print(processMacros(read('corruptionCheck.js'))); + } if (HEADLESS) { print('if (!ENVIRONMENT_IS_WEB) {'); print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace('%s,', 'null,').replace('%d', '0')); diff --git a/src/library.js b/src/library.js index 3d00a4d5..d5f11cf3 100644 --- a/src/library.js +++ b/src/library.js @@ -504,7 +504,7 @@ LibraryManager.library = { } var utf8 = new Runtime.UTF8Processor(); function simpleOutput(val) { - if (val === null || val === '\n'.charCodeAt(0)) { + if (val === null || val === {{{ charCode('\n') }}}) { output.printer(output.buffer.join('')); output.buffer = []; } else { @@ -600,8 +600,8 @@ LibraryManager.library = { quit: function() { if (!FS.init.initialized) return; // Flush any partially-printed lines in stdout and stderr. Careful, they may have been closed - if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output('\n'.charCodeAt(0)); - if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output('\n'.charCodeAt(0)); + if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output({{{ charCode('\n') }}}); + if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output({{{ charCode('\n') }}}); }, // Standardizes a path. Useful for making comparisons of pathnames work in a consistent manner. @@ -828,11 +828,11 @@ LibraryManager.library = { // Null or empty results in '.'. var me = ___libgenSplitName; if (!me.ret) { - me.ret = allocate(['.'.charCodeAt(0), 0], 'i8', ALLOC_NORMAL); + me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL); } return [me.ret, -1]; } else { - var slash = '/'.charCodeAt(0); + var slash = {{{ charCode('/') }}}; var allSlashes = true; var slashPositions = []; for (var i = 0; {{{ makeGetValue('path', 'i', 'i8') }}} !== 0; i++) { @@ -1730,7 +1730,12 @@ LibraryManager.library = { } var contents = stream.object.contents; var size = Math.min(contents.length - offset, nbyte); - if (contents.subarray || contents.slice) { // typed array or normal array +#if USE_TYPED_ARRAYS == 2 + if (contents.subarray) { // typed array + HEAPU8.set(contents.subarray(offset, offset+size), buf); + } else +#endif + if (contents.slice) { // normal array for (var i = 0; i < size; i++) { {{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}} } @@ -2452,9 +2457,9 @@ LibraryManager.library = { _scanString: function(format, get, unget, varargs) { if (!__scanString.whiteSpace) { __scanString.whiteSpace = {}; - __scanString.whiteSpace[' '.charCodeAt(0)] = 1; - __scanString.whiteSpace['\t'.charCodeAt(0)] = 1; - __scanString.whiteSpace['\n'.charCodeAt(0)] = 1; + __scanString.whiteSpace[{{{ charCode(' ') }}}] = 1; + __scanString.whiteSpace[{{{ charCode('\t') }}}] = 1; + __scanString.whiteSpace[{{{ charCode('\n') }}}] = 1; __scanString.whiteSpace[' '] = 1; __scanString.whiteSpace['\t'] = 1; __scanString.whiteSpace['\n'] = 1; @@ -2514,8 +2519,8 @@ LibraryManager.library = { if (format[formatIndex] === '%') { formatIndex++; var maxSpecifierStart = formatIndex; - while (format[formatIndex].charCodeAt(0) >= '0'.charCodeAt(0) && - format[formatIndex].charCodeAt(0) <= '9'.charCodeAt(0)) { + while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} && + format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) { formatIndex++; } var max_; @@ -2561,11 +2566,11 @@ LibraryManager.library = { while ((curr < max_ || isNaN(max_)) && next > 0) { if (!(next in __scanString.whiteSpace) && // stop on whitespace (type == 's' || - ((type === 'd' || type == 'u' || type == 'i') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) || - (first && next == '-'.charCodeAt(0)))) || - (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) || - next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) || - next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) && + ((type === 'd' || type == 'u' || type == 'i') && ((next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) || + (first && next == {{{ charCode('-') }}}))) || + (type === 'x' && (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}} || + next >= {{{ charCode('a') }}} && next <= {{{ charCode('f') }}} || + next >= {{{ charCode('A') }}} && next <= {{{ charCode('F') }}}))) && (formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up buffer.push(String.fromCharCode(next)); next = get(); @@ -2633,7 +2638,7 @@ LibraryManager.library = { } return fields; }, - // Performs prtinf-style formatting. + // Performs printf-style formatting. // format: A pointer to the format string. // varargs: A pointer to the start of the arguments list. // Returns the resulting string string as a character array. @@ -2670,7 +2675,7 @@ LibraryManager.library = { curr = {{{ makeGetValue(0, 'textIndex', 'i8') }}}; if (curr === 0) break; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (curr == '%'.charCodeAt(0)) { + if (curr == {{{ charCode('%') }}}) { // Handle flags. var flagAlwaysSigned = false; var flagLeftAlign = false; @@ -2678,16 +2683,16 @@ LibraryManager.library = { var flagZeroPad = false; flagsLoop: while (1) { switch (next) { - case '+'.charCodeAt(0): + case {{{ charCode('+') }}}: flagAlwaysSigned = true; break; - case '-'.charCodeAt(0): + case {{{ charCode('-') }}}: flagLeftAlign = true; break; - case '#'.charCodeAt(0): + case {{{ charCode('#') }}}: flagAlternative = true; break; - case '0'.charCodeAt(0): + case {{{ charCode('0') }}}: if (flagZeroPad) { break flagsLoop; } else { @@ -2703,13 +2708,13 @@ LibraryManager.library = { // Handle width. var width = 0; - if (next == '*'.charCodeAt(0)) { + if (next == {{{ charCode('*') }}}) { width = getNextArg('i32'); textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; } else { - while (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) { - width = width * 10 + (next - '0'.charCodeAt(0)); + while (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) { + width = width * 10 + (next - {{{ charCode('0') }}}); textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; } @@ -2717,20 +2722,20 @@ LibraryManager.library = { // Handle precision. var precisionSet = false; - if (next == '.'.charCodeAt(0)) { + if (next == {{{ charCode('.') }}}) { var precision = 0; precisionSet = true; textIndex++; next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (next == '*'.charCodeAt(0)) { + if (next == {{{ charCode('*') }}}) { precision = getNextArg('i32'); textIndex++; } else { while(1) { var precisionChr = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; - if (precisionChr < '0'.charCodeAt(0) || - precisionChr > '9'.charCodeAt(0)) break; - precision = precision * 10 + (precisionChr - '0'.charCodeAt(0)); + if (precisionChr < {{{ charCode('0') }}} || + precisionChr > {{{ charCode('9') }}}) break; + precision = precision * 10 + (precisionChr - {{{ charCode('0') }}}); textIndex++; } } @@ -2744,7 +2749,7 @@ LibraryManager.library = { switch (String.fromCharCode(next)) { case 'h': var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}}; - if (nextNext == 'h'.charCodeAt(0)) { + if (nextNext == {{{ charCode('h') }}}) { textIndex++; argSize = 1; // char (actually i32 in varargs) } else { @@ -2753,7 +2758,7 @@ LibraryManager.library = { break; case 'l': var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}}; - if (nextNext = |