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 == 'l'.charCodeAt(0)) { + if (nextNext == {{{ charCode('l') }}}) { textIndex++; argSize = 8; // long long } else { @@ -2777,226 +2782,249 @@ LibraryManager.library = { next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}}; // Handle type specifier. - if (['d', 'i', 'u', 'o', 'x', 'X', 'p'].indexOf(String.fromCharCode(next)) != -1) { - // Integer. - var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0); - argSize = argSize || 4; - var currArg = getNextArg('i' + (argSize * 8)); + switch (String.fromCharCode(next)) { + case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': { + // Integer. + var signed = next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}; + argSize = argSize || 4; + var currArg = getNextArg('i' + (argSize * 8)); #if PRECISE_I64_MATH - var origArg = currArg; + var origArg = currArg; #endif - var argText; + var argText; #if USE_TYPED_ARRAYS == 2 - // Flatten i64-1 [low, high] into a (slightly rounded) double - if (argSize == 8) { - currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 'u'.charCodeAt(0)); - } + // Flatten i64-1 [low, high] into a (slightly rounded) double + if (argSize == 8) { + currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == {{{ charCode('u') }}}); + } #endif - // Truncate to requested size. - if (argSize <= 4) { - var limit = Math.pow(256, argSize) - 1; - currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); - } - // Format the number. - var currAbsArg = Math.abs(currArg); - var prefix = ''; - if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) { + // Truncate to requested size. + if (argSize <= 4) { + var limit = Math.pow(256, argSize) - 1; + currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8); + } + // Format the number. + var currAbsArg = Math.abs(currArg); + var prefix = ''; + if (next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}) { #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else + if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else #endif - argText = reSign(currArg, 8 * argSize, 1).toString(10); - } else if (next == 'u'.charCodeAt(0)) { + argText = reSign(currArg, 8 * argSize, 1).toString(10); + } else if (next == {{{ charCode('u') }}}) { #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else + if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else #endif - argText = unSign(currArg, 8 * argSize, 1).toString(10); - currArg = Math.abs(currArg); - } else if (next == 'o'.charCodeAt(0)) { - argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); - } else if (next == 'x'.charCodeAt(0) || next == 'X'.charCodeAt(0)) { - prefix = flagAlternative ? '0x' : ''; + argText = unSign(currArg, 8 * argSize, 1).toString(10); + currArg = Math.abs(currArg); + } else if (next == {{{ charCode('o') }}}) { + argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); + } else if (next == {{{ charCode('x') }}} || next == {{{ charCode('X') }}}) { + prefix = flagAlternative ? '0x' : ''; #if PRECISE_I64_MATH - if (argSize == 8 && i64Math) argText = (origArg[1]>>>0).toString(16) + (origArg[0]>>>0).toString(16); else + if (argSize == 8 && i64Math) { + if (origArg[1]) { + argText = (origArg[1]>>>0).toString(16); + var lower = (origArg[0]>>>0).toString(16); + while (lower.length < 8) lower = '0' + lower; + argText += lower; + } else { + argText = (origArg[0]>>>0).toString(16); + } + } else #endif - if (currArg < 0) { - // Represent negative numbers in hex as 2's complement. - currArg = -currArg; - argText = (currAbsArg - 1).toString(16); - var buffer = []; - for (var i = 0; i < argText.length; i++) { - buffer.push((0xF - parseInt(argText[i], 16)).toString(16)); + if (currArg < 0) { + // Represent negative numbers in hex as 2's complement. + currArg = -currArg; + argText = (currAbsArg - 1).toString(16); + var buffer = []; + for (var i = 0; i < argText.length; i++) { + buffer.push((0xF - parseInt(argText[i], 16)).toString(16)); + } + argText = buffer.join(''); + while (argText.length < argSize * 2) argText = 'f' + argText; + } else { + argText = currAbsArg.toString(16); + } + if (next == {{{ charCode('X') }}}) { + prefix = prefix.toUpperCase(); + argText = argText.toUpperCase(); + } + } else if (next == {{{ charCode('p') }}}) { + if (currAbsArg === 0) { + argText = '(nil)'; + } else { + prefix = '0x'; + argText = currAbsArg.toString(16); } - argText = buffer.join(''); - while (argText.length < argSize * 2) argText = 'f' + argText; - } else { - argText = currAbsArg.toString(16); - } - if (next == 'X'.charCodeAt(0)) { - prefix = prefix.toUpperCase(); - argText = argText.toUpperCase(); - } - } else if (next == 'p'.charCodeAt(0)) { - if (currAbsArg === 0) { - argText = '(nil)'; - } else { - prefix = '0x'; - argText = currAbsArg.toString(16); } - } - if (precisionSet) { - while (argText.length < precision) { - argText = '0' + argText; + if (precisionSet) { + while (argText.length < precision) { + argText = '0' + argText; + } } - } - // Add sign if needed - if (flagAlwaysSigned) { - if (currArg < 0) { - prefix = '-' + prefix; - } else { - prefix = '+' + prefix; + // Add sign if needed + if (flagAlwaysSigned) { + if (currArg < 0) { + prefix = '-' + prefix; + } else { + prefix = '+' + prefix; + } } - } - // Add padding. - while (prefix.length + argText.length < width) { - if (flagLeftAlign) { - argText += ' '; - } else { - if (flagZeroPad) { - argText = '0' + argText; + // Add padding. + while (prefix.length + argText.length < width) { + if (flagLeftAlign) { + argText += ' '; } else { - prefix = ' ' + prefix; + if (flagZeroPad) { + argText = '0' + argText; + } else { + prefix = ' ' + prefix; + } } } + + // Insert the result into the buffer. + argText = prefix + argText; + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; } + case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': { + // Float. + var currArg = getNextArg('double'); + var argText; + + if (isNaN(currArg)) { + argText = 'nan'; + flagZeroPad = false; + } else if (!isFinite(currArg)) { + argText = (currArg < 0 ? '-' : '') + 'inf'; + flagZeroPad = false; + } else { + var isGeneral = false; + var effectivePrecision = Math.min(precision, 20); + + // Convert g/G to f/F or e/E, as per: + // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html + if (next == {{{ charCode('g') }}} || next == {{{ charCode('G') }}}) { + isGeneral = true; + precision = precision || 1; + var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10); + if (precision > exponent && exponent >= -4) { + next = ((next == {{{ charCode('g') }}}) ? 'f' : 'F').charCodeAt(0); + precision -= exponent + 1; + } else { + next = ((next == {{{ charCode('g') }}}) ? 'e' : 'E').charCodeAt(0); + precision--; + } + effectivePrecision = Math.min(precision, 20); + } - // Insert the result into the buffer. - argText = prefix + argText; - argText.split('').forEach(function(chr) { - ret.push(chr.charCodeAt(0)); - }); - } else if (['f', 'F', 'e', 'E', 'g', 'G'].indexOf(String.fromCharCode(next)) != -1) { - // Float. - var currArg = getNextArg('double'); - var argText; - - if (isNaN(currArg)) { - argText = 'nan'; - flagZeroPad = false; - } else if (!isFinite(currArg)) { - argText = (currArg < 0 ? '-' : '') + 'inf'; - flagZeroPad = false; - } else { - var isGeneral = false; - var effectivePrecision = Math.min(precision, 20); - - // Convert g/G to f/F or e/E, as per: - // http://pubs.opengroup.org/onlinepubs/9699919799/functions/printf.html - if (next == 'g'.charCodeAt(0) || next == 'G'.charCodeAt(0)) { - isGeneral = true; - precision = precision || 1; - var exponent = parseInt(currArg.toExponential(effectivePrecision).split('e')[1], 10); - if (precision > exponent && exponent >= -4) { - next = ((next == 'g'.charCodeAt(0)) ? 'f' : 'F').charCodeAt(0); - precision -= exponent + 1; + if (next == {{{ charCode('e') }}} || next == {{{ charCode('E') }}}) { + argText = currArg.toExponential(effectivePrecision); + // Make sure the exponent has at least 2 digits. + if (/[eE][-+]\d$/.test(argText)) { + argText = argText.slice(0, -1) + '0' + argText.slice(-1); + } + } else if (next == {{{ charCode('f') }}} || next == {{{ charCode('F') }}}) { + argText = currArg.toFixed(effectivePrecision); + } + + var parts = argText.split('e'); + if (isGeneral && !flagAlternative) { + // Discard trailing zeros and periods. + while (parts[0].length > 1 && parts[0].indexOf('.') != -1 && + (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) { + parts[0] = parts[0].slice(0, -1); + } } else { - next = ((next == 'g'.charCodeAt(0)) ? 'e' : 'E').charCodeAt(0); - precision--; + // Make sure we have a period in alternative mode. + if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.'; + // Zero pad until required precision. + while (precision > effectivePrecision++) parts[0] += '0'; } - effectivePrecision = Math.min(precision, 20); - } + argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : ''); + + // Capitalize 'E' if needed. + if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase(); - if (next == 'e'.charCodeAt(0) || next == 'E'.charCodeAt(0)) { - argText = currArg.toExponential(effectivePrecision); - // Make sure the exponent has at least 2 digits. - if (/[eE][-+]\d$/.test(argText)) { - argText = argText.slice(0, -1) + '0' + argText.slice(-1); + // Add sign. + if (flagAlwaysSigned && currArg >= 0) { + argText = '+' + argText; } - } else if (next == 'f'.charCodeAt(0) || next == 'F'.charCodeAt(0)) { - argText = currArg.toFixed(effectivePrecision); } - var parts = argText.split('e'); - if (isGeneral && !flagAlternative) { - // Discard trailing zeros and periods. - while (parts[0].length > 1 && parts[0].indexOf('.') != -1 && - (parts[0].slice(-1) == '0' || parts[0].slice(-1) == '.')) { - parts[0] = parts[0].slice(0, -1); + // Add padding. + while (argText.length < width) { + if (flagLeftAlign) { + argText += ' '; + } else { + if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) { + argText = argText[0] + '0' + argText.slice(1); + } else { + argText = (flagZeroPad ? '0' : ' ') + argText; + } } - } else { - // Make sure we have a period in alternative mode. - if (flagAlternative && argText.indexOf('.') == -1) parts[0] += '.'; - // Zero pad until required precision. - while (precision > effectivePrecision++) parts[0] += '0'; } - argText = parts[0] + (parts.length > 1 ? 'e' + parts[1] : ''); - // Capitalize 'E' if needed. - if (next == 'E'.charCodeAt(0)) argText = argText.toUpperCase(); + // Adjust case. + if (next < {{{ charCode('a') }}}) argText = argText.toUpperCase(); - // Add sign. - if (flagAlwaysSigned && currArg >= 0) { - argText = '+' + argText; - } + // Insert the result into the buffer. + argText.split('').forEach(function(chr) { + ret.push(chr.charCodeAt(0)); + }); + break; } - - // Add padding. - while (argText.length < width) { + case 's': { + // String. + var arg = getNextArg('i8*') || nullString; + var argLength = _strlen(arg); + if (precisionSet) argLength = Math.min(argLength, precision); + if (!flagLeftAlign) { + while (argLength < width--) { + ret.push({{{ charCode(' ') }}}); + } + } + for (var i = 0; i < argLength; i++) { + ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); + } if (flagLeftAlign) { - argText += ' '; - } else { - if (flagZeroPad && (argText[0] == '-' || argText[0] == '+')) { - argText = argText[0] + '0' + argText.slice(1); - } else { - argText = (flagZeroPad ? '0' : ' ') + argText; + while (argLength < width--) { + ret.push({{{ charCode(' ') }}}); } } + break; } - - // Adjust case. - if (next < 'a'.charCodeAt(0)) argText = argText.toUpperCase(); - - // Insert the result into the buffer. - argText.split('').forEach(function(chr) { - ret.push(chr.charCodeAt(0)); - }); - } else if (next == 's'.charCodeAt(0)) { - // String. - var arg = getNextArg('i8*') || nullString; - var argLength = _strlen(arg); - if (precisionSet) argLength = Math.min(argLength, precision); - if (!flagLeftAlign) { - while (argLength < width--) { - ret.push(' '.charCodeAt(0)); + case 'c': { + // Character. + if (flagLeftAlign) ret.push(getNextArg('i8')); + while (--width > 0) { + ret.push({{{ charCode(' ') }}}); } + if (!flagLeftAlign) ret.push(getNextArg('i8')); + break; } - for (var i = 0; i < argLength; i++) { - ret.push({{{ makeGetValue('arg++', 0, 'i8', null, true) }}}); - } - if (flagLeftAlign) { - while (argLength < width--) { - ret.push(' '.charCodeAt(0)); - } + case 'n': { + // Write the length written so far to the next parameter. + var ptr = getNextArg('i32*'); + {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}} + break; } - } else if (next == 'c'.charCodeAt(0)) { - // Character. - if (flagLeftAlign) ret.push(getNextArg('i8')); - while (--width > 0) { - ret.push(' '.charCodeAt(0)); + case '%': { + // Literal percent sign. + ret.push(curr); + break; } - if (!flagLeftAlign) ret.push(getNextArg('i8')); - } else if (next == 'n'.charCodeAt(0)) { - // Write the length written so far to the next parameter. - var ptr = getNextArg('i32*'); - {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}} - } else if (next == '%'.charCodeAt(0)) { - // Literal percent sign. - ret.push(curr); - } else { - // Unknown specifiers remain untouched. - for (var i = startTextIndex; i < textIndex + 2; i++) { - ret.push({{{ makeGetValue(0, 'i', 'i8') }}}); + default: { + // Unknown specifiers remain untouched. + for (var i = startTextIndex; i < textIndex + 2; i++) { + ret.push({{{ makeGetValue(0, 'i', 'i8') }}}); + } } } textIndex += 2; @@ -3139,7 +3167,7 @@ LibraryManager.library = { var streamObj = FS.streams[stream]; if (streamObj.error || streamObj.eof) return 0; var byte_; - for (var i = 0; i < n - 1 && byte_ != '\n'.charCodeAt(0); i++) { + for (var i = 0; i < n - 1 && byte_ != {{{ charCode('\n') }}}; i++) { byte_ = _fgetc(stream); if (byte_ == -1) { if (streamObj.error || (streamObj.eof && i == 0)) return 0; @@ -3245,7 +3273,7 @@ LibraryManager.library = { if (ret < 0) { return ret; } else { - var newlineRet = _fputc('\n'.charCodeAt(0), stdout); + var newlineRet = _fputc({{{ charCode('\n') }}}, stdout); return (newlineRet < 0) ? -1 : ret + 1; } }, @@ -3371,8 +3399,8 @@ LibraryManager.library = { var stdout = {{{ makeGetValue(makeGlobalUse('_stdout'), '0', 'void*') }}}; if (s) { _fputs(s, stdout); - _fputc(':'.charCodeAt(0), stdout); - _fputc(' '.charCodeAt(0), stdout); + _fputc({{{ charCode(':') }}}, stdout); + _fputc({{{ charCode(' ') }}}, stdout); } var errnum = {{{ makeGetValue('___errno_location()', '0', 'i32') }}}; _puts(_strerror(errnum)); @@ -3745,19 +3773,19 @@ LibraryManager.library = { // Check for a plus/minus sign. var multiplier = 1; - if ({{{ makeGetValue('str', 0, 'i8') }}} == '-'.charCodeAt(0)) { + if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) { multiplier = -1; str++; - } else if ({{{ makeGetValue('str', 0, 'i8') }}} == '+'.charCodeAt(0)) { + } else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) { str++; } // Find base. var finalBase = base; if (!finalBase) { - if ({{{ makeGetValue('str', 0, 'i8') }}} == '0'.charCodeAt(0)) { - if ({{{ makeGetValue('str+1', 0, 'i8') }}} == 'x'.charCodeAt(0) || - {{{ makeGetValue('str+1', 0, 'i8') }}} == 'X'.charCodeAt(0)) { + if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) { + if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} || + {{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) { finalBase = 16; str += 2; } else { @@ -3821,9 +3849,9 @@ LibraryManager.library = { while (_isspace({{{ makeGetValue('str', 0, 'i8') }}})) str++; // Check for a plus/minus sign. - if ({{{ makeGetValue('str', 0, 'i8') }}} == '-'.charCodeAt(0)) { + if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('-') }}}) { str++; - } else if ({{{ makeGetValue('str', 0, 'i8') }}} == '+'.charCodeAt(0)) { + } else if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('+') }}}) { str++; } @@ -3831,9 +3859,9 @@ LibraryManager.library = { var ok = false; var finalBase = base; if (!finalBase) { - if ({{{ makeGetValue('str', 0, 'i8') }}} == '0'.charCodeAt(0)) { - if ({{{ makeGetValue('str+1', 0, 'i8') }}} == 'x'.charCodeAt(0) || - {{{ makeGetValue('str+1', 0, 'i8') }}} == 'X'.charCodeAt(0)) { + if ({{{ makeGetValue('str', 0, 'i8') }}} == {{{ charCode('0') }}}) { + if ({{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('x') }}} || + {{{ makeGetValue('str+1', 0, 'i8') }}} == {{{ charCode('X') }}}) { finalBase = 16; str += 2; } else { @@ -4163,7 +4191,7 @@ LibraryManager.library = { return ret; }, - memcpy__asm: 'true', + memcpy__asm: true, memcpy__sig: 'iiii', memcpy: function (dest, src, num) { dest = dest|0; src = src|0; num = num|0; @@ -4324,14 +4352,18 @@ LibraryManager.library = { } }, + strcpy__asm: true, + strcpy__sig: 'iii', strcpy: function(pdest, psrc) { + pdest = pdest|0; psrc = psrc|0; var i = 0; do { - {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}}; - i ++; - } while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0); - return pdest; + {{{ makeCopyValues('(pdest+i)|0', '(psrc+i)|0', 1, 'i8', null, 1) }}}; + i = (i+1)|0; + } while (({{{ makeGetValue('psrc', 'i-1', 'i8') }}})|0 != 0); + return pdest|0; }, + stpcpy: function(pdest, psrc) { var i = 0; do { @@ -4341,14 +4373,18 @@ LibraryManager.library = { return pdest + i - 1; }, + strncpy__asm: true, + strncpy__sig: 'iiii', strncpy: function(pdest, psrc, num) { - var padding = false, curr; - for (var i = 0; i < num; i++) { - curr = padding ? 0 : {{{ makeGetValue('psrc', 'i', 'i8') }}}; + pdest = pdest|0; psrc = psrc|0; num = num|0; + var padding = 0, curr = 0, i = 0; + while ((i|0) < (num|0)) { + curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}}; {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}} - padding = padding || {{{ makeGetValue('psrc', 'i', 'i8') }}} == 0; + padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0); + i = (i+1)|0; } - return pdest; + return pdest|0; }, strlwr__deps:['tolower'], @@ -4373,15 +4409,18 @@ LibraryManager.library = { } }, + strcat__asm: true, + strcat__sig: 'iii', strcat__deps: ['strlen'], strcat: function(pdest, psrc) { - var len = _strlen(pdest); + pdest = pdest|0; psrc = psrc|0; var i = 0; + pdest = (pdest + _strlen(pdest))|0; do { - {{{ makeCopyValues('pdest+len+i', 'psrc+i', 1, 'i8', null, 1) }}}; - i ++; - } while ({{{ makeGetValue('psrc', 'i-1', 'i8') }}} != 0); - return pdest; + {{{ makeCopyValues('pdest+i', 'psrc+i', 1, 'i8', null, 1) }}}; + i = (i+1)|0; + } while ({{{ makeGetValueAsm('psrc', 'i-1', 'i8') }}} != 0); + return pdest|0; }, strncat__deps: ['strlen'], @@ -4407,9 +4446,12 @@ LibraryManager.library = { // We always assume ASCII locale. strcoll: 'strcmp', + strcasecmp__asm: true, + strcasecmp__sig: 'iii', strcasecmp__deps: ['strncasecmp'], strcasecmp: function(px, py) { - return _strncasecmp(px, py, TOTAL_MEMORY); + px = px|0; py = py|0; + return _strncasecmp(px, py, -1)|0; }, strncmp: function(px, py, n) { @@ -4430,26 +4472,29 @@ LibraryManager.library = { return 0; }, + strncasecmp__asm: true, + strncasecmp__sig: 'iiii', strncasecmp__deps: ['tolower'], strncasecmp: function(px, py, n) { - var i = 0; - while (i < n) { - var x = _tolower({{{ makeGetValue('px', 'i', 'i8', 0, 1) }}}); - var y = _tolower({{{ makeGetValue('py', 'i', 'i8', 0, 1) }}}); - if (x == y && x == 0) return 0; - if (x == 0) return -1; - if (y == 0) return 1; - if (x == y) { - i ++; + px = px|0; py = py|0; n = n|0; + var i = 0, x = 0, y = 0; + while ((i>>>0) < (n>>>0)) { + x = _tolower({{{ makeGetValueAsm('px', 'i', 'i8', 0, 1) }}}); + y = _tolower({{{ makeGetValueAsm('py', 'i', 'i8', 0, 1) }}}); + if (((x|0) == (y|0)) & ((x|0) == 0)) return 0; + if ((x|0) == 0) return -1; + if ((y|0) == 0) return 1; + if ((x|0) == (y|0)) { + i = (i + 1)|0; continue; } else { - return x > y ? 1 : -1; + return ((x>>>0) > (y>>>0) ? 1 : -1)|0; } } return 0; }, - memcmp__asm: 'true', + memcmp__asm: true, memcmp__sig: 'iiii', memcmp: function(p1, p2, num) { p1 = p1|0; p2 = p2|0; num = num|0; @@ -4651,58 +4696,61 @@ LibraryManager.library = { return chr & 0x7F; }, toupper: function(chr) { - if (chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0)) { - return chr - 'a'.charCodeAt(0) + 'A'.charCodeAt(0); + if (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) { + return chr - {{{ charCode('a') }}} + {{{ charCode('A') }}}; } else { return chr; } }, _toupper: 'toupper', + + tolower__asm: true, + tolower__sig: 'ii', tolower: function(chr) { - if (chr >= 'A'.charCodeAt(0) && chr <= 'Z'.charCodeAt(0)) { - return chr - 'A'.charCodeAt(0) + 'a'.charCodeAt(0); - } else { - return chr; - } + chr = chr|0; + if ((chr|0) < {{{ charCode('A') }}}) return chr|0; + if ((chr|0) > {{{ charCode('Z') }}}) return chr|0; + return (chr - {{{ charCode('A') }}} + {{{ charCode('a') }}})|0; }, _tolower: 'tolower', + // The following functions are defined as macros in glibc. islower: function(chr) { - return chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0); + return chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}; }, isupper: function(chr) { - return chr >= 'A'.charCodeAt(0) && chr <= 'Z'.charCodeAt(0); + return chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}; }, isalpha: function(chr) { - return (chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0)) || - (chr >= 'A'.charCodeAt(0) && chr <= 'Z'.charCodeAt(0)); + return (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) || + (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}); }, isdigit: function(chr) { - return chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0); + return chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}; }, isdigit_l: 'isdigit', // no locale support yet isxdigit: function(chr) { - return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || - (chr >= 'a'.charCodeAt(0) && chr <= 'f'.charCodeAt(0)) || - (chr >= 'A'.charCodeAt(0) && chr <= 'F'.charCodeAt(0)); + return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) || + (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('f') }}}) || + (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('F') }}}); }, isxdigit_l: 'isxdigit', // no locale support yet isalnum: function(chr) { - return (chr >= '0'.charCodeAt(0) && chr <= '9'.charCodeAt(0)) || - (chr >= 'a'.charCodeAt(0) && chr <= 'z'.charCodeAt(0)) || - (chr >= 'A'.charCodeAt(0) && chr <= 'Z'.charCodeAt(0)); + return (chr >= {{{ charCode('0') }}} && chr <= {{{ charCode('9') }}}) || + (chr >= {{{ charCode('a') }}} && chr <= {{{ charCode('z') }}}) || + (chr >= {{{ charCode('A') }}} && chr <= {{{ charCode('Z') }}}); }, ispunct: function(chr) { - return (chr >= '!'.charCodeAt(0) && chr <= '/'.charCodeAt(0)) || - (chr >= ':'.charCodeAt(0) && chr <= '@'.charCodeAt(0)) || - (chr >= '['.charCodeAt(0) && chr <= '`'.charCodeAt(0)) || - (chr >= '{'.charCodeAt(0) && chr <= '~'.charCodeAt(0)); + return (chr >= {{{ charCode('!') }}} && chr <= {{{ charCode('/') }}}) || + (chr >= {{{ charCode(':') }}} && chr <= {{{ charCode('@') }}}) || + (chr >= {{{ charCode('[') }}} && chr <= {{{ charCode('`') }}}) || + (chr >= {{{ charCode('{') }}} && chr <= {{{ charCode('~') }}}); }, isspace: function(chr) { return chr in { 32: 0, 9: 0, 10: 0, 11: 0, 12: 0, 13: 0 }; }, isblank: function(chr) { - return chr == ' '.charCodeAt(0) || chr == '\t'.charCodeAt(0); + return chr == {{{ charCode(' ') }}} || chr == {{{ charCode('\t') }}}; }, iscntrl: function(chr) { return (0 <= chr && chr <= 0x1F) || chr === 0x7F; @@ -5206,13 +5254,6 @@ LibraryManager.library = { {{{ makeStructuralReturn(['(x*y)>>>0', 'x*y > 4294967295']) }}}; }, - llvm_uadd_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], - llvm_uadd_with_overflow_i64: function(xl, xh, yl, yh) { - i64Math.add(xl, xh, yl, yh); - {{{ makeStructuralReturn([makeGetTempDouble(0, 'i32'), makeGetTempDouble(1, 'i32'), '0']) }}}; - // XXX Need to hack support for second param in long.js - }, - llvm_umul_with_overflow_i64__deps: [function() { Types.preciseI64MathUsed = 1 }], llvm_umul_with_overflow_i64: function(xl, xh, yl, yh) { i64Math.multiply(xl, xh, yl, yh); @@ -7352,6 +7393,81 @@ LibraryManager.library = { Module.print(intArrayToString(__formatString(_emscripten_jcache_printf_.buffer, varargs + i*4)).replace('\\n', '')); Runtime.stackAlloc(-4*i); // free up the stack space we know is ok to free }, + + //============================ + // i64 math + //============================ + + i64Add__asm: true, + i64Add__sig: 'iiiii', + i64Add: function(a, b, c, d) { + /* + x = a + b*2^32 + y = c + d*2^32 + result = l + h*2^32 + */ + a = a|0; b = b|0; c = c|0; d = d|0; + var l = 0, h = 0; + l = (a + c)>>>0; + h = (b + d)>>>0; + if ((l>>>0) < (a>>>0)) { // iff we overflowed + h = (h+1)>>>0; + } + {{{ makeStructuralReturn(['l|0', 'h'], true) }}}; + }, + llvm_uadd_with_overflow_i64__asm: true, + llvm_uadd_with_overflow_i64__sig: 'iiiii', + llvm_uadd_with_overflow_i64: function(a, b, c, d) { + a = a|0; b = b|0; c = c|0; d = d|0; + var l = 0, h = 0, overflow = 0; + l = (a + c)>>>0; + h = (b + d)>>>0; + if ((l>>>0) < (a>>>0)) { // iff we overflowed + h = (h+1)>>>0; + overflow = 1; + } + {{{ makeStructuralReturn(['l|0', 'h', 'overflow'], true) }}}; + }, + + bitshift64Shl__asm: true, + bitshift64Shl__sig: 'iiii', + bitshift64Shl: function(low, high, bits) { + low = low|0; high = high|0; bits = bits|0; + var ander = 0; + if ((bits|0) < 32) { + ander = ((1 << bits) - 1)|0; + tempRet0 = (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits)); + return low << bits; + } + tempRet0 = low << (bits - 32); + return 0; + }, + bitshift64Ashr__asm: true, + bitshift64Ashr__sig: 'iiii', + bitshift64Ashr: function(low, high, bits) { + low = low|0; high = high|0; bits = bits|0; + var ander = 0; + if ((bits|0) < 32) { + ander = ((1 << bits) - 1)|0; + tempRet0 = high >> bits; + return (low >>> bits) | ((high&ander) << (32 - bits)); + } + tempRet0 = (high|0) < 0 ? -1 : 0; + return (high >> (bits - 32))|0; + }, + bitshift64Lshr__asm: true, + bitshift64Lshr__sig: 'iiii', + bitshift64Lshr: function(low, high, bits) { + low = low|0; high = high|0; bits = bits|0; + var ander = 0; + if ((bits|0) < 32) { + ander = ((1 << bits) - 1)|0; + tempRet0 = high >>> bits; + return (low >>> bits) | ((high&ander) << (32 - bits)); + } + tempRet0 = 0; + return (high >>> (bits - 32))|0; + }, }; function autoAddDeps(object, name) { @@ -7363,3 +7479,4 @@ function autoAddDeps(object, name) { } } + diff --git a/src/library_gl.js b/src/library_gl.js index 9e12e4ee..297a36cf 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -58,7 +58,12 @@ var LibraryGL = { return ret; }, - // Temporary buffers + // Mini temp buffer + MINI_TEMP_BUFFER_SIZE: 16, + miniTempBuffer: null, + miniTempBufferViews: [0], // index i has the view of size i+1 + + // Large temporary buffers MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}}, tempBufferIndexLookup: null, tempVertexBuffers: null, @@ -311,6 +316,11 @@ var LibraryGL = { if (!Module.useWebGL) return; // an app might link both gl and 2d backends + GL.miniTempBuffer = new Float32Array(GL.MINI_TEMP_BUFFER_SIZE); + for (var i = 0; i < GL.MINI_TEMP_BUFFER_SIZE; i++) { + GL.miniTempBufferViews[i] = GL.miniTempBuffer.subarray(0, i+1); + } + GL.maxVertexAttribs = Module.ctx.getParameter(Module.ctx.MAX_VERTEX_ATTRIBS); #if FULL_ES2 for (var i = 0; i < GL.maxVertexAttribs; i++) { @@ -832,53 +842,108 @@ var LibraryGL = { glUniform1fv__sig: 'viii', glUniform1fv: function(location, count, value) { location = GL.uniforms[location]; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniform1fv(location, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform + view = GL.miniTempBufferViews[0]; + view[0] = {{{ makeGetValue('value', '0', 'float') }}}; + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; + } + Module.ctx.uniform1fv(location, view); }, glUniform2fv__sig: 'viii', glUniform2fv: function(location, count, value) { location = GL.uniforms[location]; - count *= 2; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniform2fv(location, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform + view = GL.miniTempBufferViews[1]; + view[0] = {{{ makeGetValue('value', '0', 'float') }}}; + view[1] = {{{ makeGetValue('value', '4', 'float') }}}; + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*8') }}}; + } + Module.ctx.uniform2fv(location, view); }, glUniform3fv__sig: 'viii', glUniform3fv: function(location, count, value) { location = GL.uniforms[location]; - count *= 3; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniform3fv(location, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform + view = GL.miniTempBufferViews[2]; + view[0] = {{{ makeGetValue('value', '0', 'float') }}}; + view[1] = {{{ makeGetValue('value', '4', 'float') }}}; + view[2] = {{{ makeGetValue('value', '8', 'float') }}}; + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*12') }}}; + } + Module.ctx.uniform3fv(location, view); }, glUniform4fv__sig: 'viii', glUniform4fv: function(location, count, value) { location = GL.uniforms[location]; - count *= 4; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniform4fv(location, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform + view = GL.miniTempBufferViews[3]; + view[0] = {{{ makeGetValue('value', '0', 'float') }}}; + view[1] = {{{ makeGetValue('value', '4', 'float') }}}; + view[2] = {{{ makeGetValue('value', '8', 'float') }}}; + view[3] = {{{ makeGetValue('value', '12', 'float') }}}; + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}}; + } + Module.ctx.uniform4fv(location, view); }, glUniformMatrix2fv: function(location, count, transpose, value) { location = GL.uniforms[location]; - count *= 4; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniformMatrix2fv(location, transpose, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform matrix + view = GL.miniTempBufferViews[3]; + for (var i = 0; i < 4; i++) { + view[i] = {{{ makeGetValue('value', 'i*4', 'float') }}}; + } + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*16') }}}; + } + Module.ctx.uniformMatrix2fv(location, transpose, view); }, glUniformMatrix3fv: function(location, count, transpose, value) { location = GL.uniforms[location]; - count *= 9; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniformMatrix3fv(location, transpose, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform matrix + view = GL.miniTempBufferViews[8]; + for (var i = 0; i < 9; i++) { + view[i] = {{{ makeGetValue('value', 'i*4', 'float') }}}; + } + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*36') }}}; + } + Module.ctx.uniformMatrix3fv(location, transpose, view); }, glUniformMatrix4fv: function(location, count, transpose, value) { location = GL.uniforms[location]; - count *= 16; - value = {{{ makeHEAPView('F32', 'value', 'value+count*4') }}}; - Module.ctx.uniformMatrix4fv(location, transpose, value); + var view; + if (count == 1) { + // avoid allocation for the common case of uploading one uniform matrix + view = GL.miniTempBufferViews[15]; + for (var i = 0; i < 16; i++) { + view[i] = {{{ makeGetValue('value', 'i*4', 'float') }}}; + } + } else { + view = {{{ makeHEAPView('F32', 'value', 'value+count*64') }}}; + } + Module.ctx.uniformMatrix4fv(location, transpose, view); }, glBindBuffer__sig: 'vii', @@ -1809,6 +1874,8 @@ var LibraryGL = { var typeIndex = attribute.type - GL.byteSizeByTypeRoot; // ensure it starts at 0 to keep the cache items dense temp = cacheItem[typeIndex]; cacheItem = temp ? temp : (cacheItem[typeIndex] = GL.immediate.rendererCacheItemTemplate.slice()); + temp = cacheItem[attribute.stride]; + cacheItem = temp ? temp : (cacheItem[attribute.stride] = GL.immediate.rendererCacheItemTemplate.slice()); } var fogParam; if (GLEmulation.fogEnabled) { diff --git a/src/library_openal.js b/src/library_openal.js new file mode 100644 index 00000000..6bd0f6b0 --- /dev/null +++ b/src/library_openal.js @@ -0,0 +1,541 @@ +//"use strict"; + +var LibraryOpenAL = { + $AL__deps: ['$Browser'], + $AL: { + contexts: [], + currentContext: null, + }, + + alcProcessContext: function(context) {}, + alcSuspendContext: function(context) {}, + + alcMakeContextCurrent: function(context) { + if (context == 0) { + AL.currentContext = null; + } else { + AL.currentContext = AL.contexts[context - 1]; + } + }, + + alcDestroyContext: function(context) { + // Stop playback, etc + }, + + alcCloseDevice: function(device) { + // Stop playback, etc + }, + + alcOpenDevice: function(deviceName) { + if (typeof(AudioContext) == "function" || + typeof(webkitAudioContext) == "function") { + return 1; // non-null pointer -- we just simulate one device + } else { + return 0; + } + }, + + alcCreateContext: function(device, attrList) { + if (device != 1) { + return 0; + } + + if (attrList) { +#if OPENAL_DEBUG + console.log("The attrList argument of alcCreateContext is not supported yet"); +#endif + return 0; + } + + var ctx; + try { + ctx = new AudioContext(); + } catch (e) { + try { + ctx = new webkitAudioContext(); + } catch (e) {} + } + + if (ctx) { + AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []}); + return AL.contexts.length; + } else { + return 0; + } + }, + + alGetError: function() { + if (!AL.currentContext) { + return 0xA004 /* AL_INVALID_OPERATION */; + } else { + return AL.currentContext.err; + } + }, + + alDeleteSources: function(count, sources) + { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alDeleteSources called without a valid context"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + var sourceIdx = {{{ makeGetValue('sources', 'i', 'i32') }}} - 1; + delete AL.currentContext.src[sourceIdx]; + } + }, + + alGenSources: function(count, sources) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGenSources called without a valid context"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + var gain = AL.currentContext.ctx.createGain(); + var panner = AL.currentContext.ctx.createPanner(); + if (typeof(webkitAudioContext) == 'function') { + gain.connect(panner); + panner.connect(AL.currentContext.ctx.destination); + } else { + // Work around a Firefox bug (bug 849916) + gain.connect(AL.currentContext.ctx.destination); + } + gain.gain.value = 1; // work around a Firefox bug (bug 850970) + AL.currentContext.src.push({ + loop: false, + buffer: null, + gain: gain, + panner: panner, + paused: false, + playTime: -1, + pausedTime: 0 + }); + {{{ makeSetValue('sources', 'i', 'AL.currentContext.src.length', 'i32') }}}; + } + }, + + alSourcei: function(source, param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourcei called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourcei called with an invalid source"); +#endif + return; + } + switch (param) { + case 0x1007 /* AL_LOOPING */: + AL.currentContext.src[source - 1].loop = (value != 0 /* AL_FALSE */); + break; + case 0x1009 /* AL_BUFFER */: + if (value == 0) { + AL.currentContext.src[source - 1].buffer = null; + } else { + AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[value - 1].buf; + } + break; + default: +#if OPENAL_DEBUG + console.log("alSourcei with param " + param + " not implemented yet"); +#endif + break; + } + }, + + alSourcef: function(source, param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourcef called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourcef called with an invalid source"); +#endif + return; + } + switch (param) { + case 0x100A /* AL_GAIN */: + AL.currentContext.src[source - 1].gain.gain.value = value; + break; + case 0x1003 /* AL_PITCH */: +#if OPENAL_DEBUG + console.log("alSourcef was called with AL_PITCH, but Web Audio does not support static pitch changes"); +#endif + break; + default: +#if OPENAL_DEBUG + console.log("alSourcef with param " + param + " not implemented yet"); +#endif + break; + } + }, + + alSourcefv: function(source, param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourcefv called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourcefv called with an invalid source"); +#endif + return; + } + switch (param) { + case 0x1004 /* AL_POSITION */: + AL.currentContext.src[source - 1].panner.setPosition( + {{{ makeGetValue('value', '0', 'float') }}}, + {{{ makeGetValue('value', '1', 'float') }}}, + {{{ makeGetValue('value', '2', 'float') }}} + ); + break; + case 0x1006 /* AL_VELOCITY */: + AL.currentContext.src[source - 1].panner.setVelocity( + {{{ makeGetValue('value', '0', 'float') }}}, + {{{ makeGetValue('value', '1', 'float') }}}, + {{{ makeGetValue('value', '2', 'float') }}} + ); + break; + default: +#if OPENAL_DEBUG + console.log("alSourcefv with param " + param + " not implemented yet"); +#endif + break; + } + }, + + alSourceQueueBuffers: function(source, count, buffers) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourceQueueBuffers called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourceQueueBuffers called with an invalid source"); +#endif + return; + } + if (count != 1) { +#if OPENAL_DEBUG + console.error("Queuing multiple buffers using alSourceQueueBuffers is not supported yet"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + var buffer = {{{ makeGetValue('buffers', 'i', 'i32') }}}; + if (buffer > AL.currentContext.buf.length) { +#if OPENAL_DEBUG + console.error("alSourceQueueBuffers called with an invalid buffer"); +#endif + return; + } + AL.currentContext.src[source - 1].buffer = AL.currentContext.buf[buffer - 1].buf; + } + }, + + alSourceUnqueueBuffers: function(source, count, buffers) + { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourceUnqueueBuffers called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourceUnqueueBuffers called with an invalid source"); +#endif + return; + } + if (count != 1) { +#if OPENAL_DEBUG + console.error("Queuing multiple buffers using alSourceUnqueueBuffers is not supported yet"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + var buffer = AL.currentContext.src[source - 1].buffer; + for (var j = 0; j < AL.currentContext.buf.length; ++j) { + if (buffer == AL.currentContext.buf[j].buf) { + {{{ makeSetValue('buffers', 'i', 'j+1', 'i32') }}}; + AL.currentContext.src[source - 1].buffer = null; + break; + } + } + } + }, + + alDeleteBuffers: function(count, buffers) + { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alDeleteBuffers called without a valid context"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + var bufferIdx = {{{ makeGetValue('buffers', 'i', 'i32') }}} - 1; + var buffer = AL.currentContext.buf[bufferIdx].buf; + for (var j = 0; j < AL.currentContext.src.length; ++j) { + if (buffer == AL.currentContext.src[j].buffer) { + AL.currentContext.err = 0xA004 /* AL_INVALID_OPERATION */; + return; + } + } + delete AL.currentContext.buf[bufferIdx]; + } + }, + + alGenBuffers: function(count, buffers) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGenBuffers called without a valid context"); +#endif + return; + } + for (var i = 0; i < count; ++i) { + AL.currentContext.buf.push({buf: null}); + {{{ makeSetValue('buffers', 'i', 'AL.currentContext.buf.length', 'i32') }}}; + } + }, + + alBufferData: function(buffer, format, data, size, freq) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alBufferData called without a valid context"); +#endif + return; + } + if (buffer > AL.currentContext.buf.length) { +#if OPENAL_DEBUG + console.error("alBufferData called with an invalid buffer"); +#endif + return; + } + var channels, bytes; + switch (format) { + case 0x1100 /* AL_FORMAT_MONO8 */: + bytes = 1; + channels = 1; + break; + case 0x1101 /* AL_FORMAT_MONO16 */: + bytes = 2; + channels = 1; + break; + case 0x1102 /* AL_FORMAT_STEREO8 */: + bytes = 1; + channels = 2; + break; + case 0x1103 /* AL_FORMAT_STEREO16 */: + bytes = 2; + channels = 2; + break; + default: +#if OPENAL_DEBUG + console.error("alBufferData called with invalid format " + format); +#endif + return; + } + AL.currentContext.buf[buffer - 1].buf = AL.currentContext.ctx.createBuffer(channels, size / (bytes * channels), freq); + var buf = new Array(channels); + for (var i = 0; i < channels; ++i) { + buf[i] = AL.currentContext.buf[buffer - 1].buf.getChannelData(i); + } + for (var i = 0; i < size / (bytes * channels); ++i) { + for (var j = 0; j < channels; ++j) { + switch (bytes) { + case 1: + var val = {{{ makeGetValue('data', 'i*channels+j', 'i8') }}}; + buf[j][i] = -1.0 + val * (2/256); + break; + case 2: + var val = {{{ makeGetValue('data', '2*(i*channels+j)', 'i16') }}}; + buf[j][i] = val/32768; + break; + } + } + } + }, + + alSourcePlay__deps: ["alSourceStop"], + alSourcePlay: function(source) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourcePlay called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourcePlay called with an invalid source"); +#endif + return; + } + var offset = 0; + if ("src" in AL.currentContext.src[source - 1]) { + // If the source is already playing, we need to resume from beginning. + // We do that by stopping the current source and replaying it. + _alSourceStop(source); + } else if (AL.currentContext.src[source - 1].paused) { + // So now we have to resume playback, remember the offset here. + offset = AL.currentContext.src[source - 1].pausedTime - + AL.currentContext.src[source - 1].playTime; + } + var src = AL.currentContext.ctx.createBufferSource(); + src.loop = AL.currentContext.src[source - 1].loop; + src.buffer = AL.currentContext.src[source - 1].buffer; + src.connect(AL.currentContext.src[source - 1].gain); + src.start(0, offset); + // Work around Firefox bug 851338 + AL.currentContext.src[source - 1].playTime = AL.currentContext.ctx.currentTime || 0; + AL.currentContext.src[source - 1].paused = false; + AL.currentContext.src[source - 1]['src'] = src; + }, + + alSourceStop: function(source) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourceStop called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourceStop called with an invalid source"); +#endif + return; + } + if ("src" in AL.currentContext.src[source - 1]) { + AL.currentContext.src[source - 1]["src"].stop(0); + delete AL.currentContext.src[source - 1]["src"]; + } + }, + + alSourcePause: function(source) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alSourcePause called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alSourcePause called with an invalid source"); +#endif + return; + } + if ("src" in AL.currentContext.src[source - 1] && + !AL.currentContext.src[source - 1].paused) { + AL.currentContext.src[source - 1].paused = true; + // Work around Firefox bug 851338 + AL.currentContext.src[source - 1].pausedTime = AL.currentContext.ctx.currentTime || 0; + AL.currentContext.src[source - 1]["src"].stop(0); + delete AL.currentContext.src[source - 1].src; + } + }, + + alGetSourcei: function(source, param, value) { + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alGetSourcei called without a valid context"); +#endif + return; + } + if (source > AL.currentContext.src.length) { +#if OPENAL_DEBUG + console.error("alGetSourcei called with an invalid source"); +#endif + return; + } + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + // Always return 1 + {{{ makeSetValue('value', '0', '1', 'i32') }}}; + break; + case 0x1009 /* AL_BUFFER */: + if (AL.currentContext.src[source - 1].buffer == null) { + {{{ makeSetValue('value', '0', '0', 'i32') }}}; + } else { + var buf = AL.currentContext.src[source - 1].buffer; + for (var i = 0; i < AL.currentContext.buf.length; ++i) { + if (buf == AL.currentContext.buf[i].buf) { + {{{ makeSetValue('value', '0', 'i+1', 'i32') }}}; + return; + } + } + {{{ makeSetValue('value', '0', '0', 'i32') }}}; + } + break; + case 0x1010 /* AL_SOURCE_STATE */: + if ("src" in AL.currentContext.src[source - 1]) { + {{{ makeSetValue('value', '0', '0x1012', 'i32') }}} /* AL_PLAYING */; + } else if (AL.currentContext.src[source - 1].paused) { + {{{ makeSetValue('value', '0', '0x1013', 'i32') }}} /* AL_PAUSED */; + } else if (AL.currentContext.src[source - 1].playTime == -1) { + {{{ makeSetValue('value', '0', '0x1011', 'i32') }}} /* AL_INITIAL */; + } else { + {{{ makeSetValue('value', '0', '0x1014', 'i32') }}} /* AL_STOPPED */; + } + break; + case 0x1015 /* AL_BUFFERS_QUEUED */: + if (AL.currentContext.src[source - 1].buffer) { + {{{ makeSetValue('value', '0', '1', 'i32') }}} + } else { + {{{ makeSetValue('value', '0', '0', 'i32') }}} + } + break; + case 0x1016 /* AL_BUFFERS_PROCESSED */: + // Always return 1 + {{{ makeSetValue('value', '0', '1', 'i32') }}} + break; + } + }, + + alDistanceModel: function(model) { + if (model != 0 /* AL_NONE */) { +#if OPENAL_DEBUG + console.log("Only alDistanceModel(AL_NONE) is currently supported"); +#endif + } + }, + + alListenerfv: function(param, values) { +#if OPENAL_DEBUG + console.log("alListenerfv is not supported yet"); +#endif + }, + + alIsExtensionPresent: function(extName) { + return 0; + }, + + alcIsExtensionPresent: function(device, extName) { + return 0; + }, + + alGetProcAddress: function(fname) { + return 0; + }, + + alcGetProcAddress: function(device, fname) { + return 0; + }, + +}; + +autoAddDeps(LibraryOpenAL, '$AL'); +mergeInto(LibraryManager.library, LibraryOpenAL); + diff --git a/src/library_sdl.js b/src/library_sdl.js index 3dbb9a33..77305609 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -35,6 +35,7 @@ var LibrarySDL = { mixerFormat: 0x8010, // AUDIO_S16LSB mixerNumChannels: 2, mixerChunkSize: 1024, + channelMinimumNumber: 0, GL: false, // Set to true if we call SDL_SetVideoMode with SDL_OPENGL, and if so, we do not create 2D canvases&contexts for blitting // Note that images loaded before SDL_SetVideoMode will not get this optimization @@ -442,6 +443,23 @@ var LibrarySDL = { return false; }, + offsetsTemp: { left: 0, top: 0 }, // temporary object to avoid generating garbage in offsets(). assumes the object is not captured + + offsets: function(element) { + var left = 0; + var top = 0; + + do { + left += element.offsetLeft; + top += element.offsetTop; + } while (element = element.offsetParent) + + var ret = SDL.offsetsTemp; + ret.left = left; + ret.top = top; + return ret; + }, + makeCEvent: function(event, ptr) { if (typeof event === 'number') { // This is a pointer to a native C event that was SDL_PushEvent'ed @@ -523,8 +541,9 @@ var LibrarySDL = { } else { // Otherwise, calculate the movement based on the changes // in the coordinates. - var x = event.pageX - Module["canvas"].offsetLeft; - var y = event.pageY - Module["canvas"].offsetTop; + var offsets = SDL.offsets(Module["canvas"]); + var x = event.pageX - offsets.left; + var y = event.pageY - offsets.top; var movementX = x - SDL.mouseX; var movementY = y - SDL.mouseY; } @@ -911,10 +930,11 @@ var LibrarySDL = { SDL_WarpMouse: function(x, y) { return; // TODO: implement this in a non-buggy way. Need to keep relative mouse movements correct after calling this + var offsets = SDL.offsets(Module["canvas"]); SDL.events.push({ type: 'mousemove', - pageX: x + Module['canvas'].offsetLeft, - pageY: y + Module['canvas'].offsetTop + pageX: x + offsets.left, + pageY: y + offsets.top }); }, @@ -1235,7 +1255,6 @@ var LibrarySDL = { Mix_Init: function(flags) { if (!flags) return 0; - SDL.channelMinimumNumber = 0; return 8; /* MIX_INIT_OGG */ }, Mix_Quit: function(){}, diff --git a/src/long.js b/src/long.js index c3651bd9..6d0e873d 100644 --- a/src/long.js +++ b/src/long.js @@ -1530,13 +1530,6 @@ var i64Math = (function() { // Emscripten wrapper // Emscripten wrapper var Wrapper = { - add: function(xl, xh, yl, yh) { - var x = new goog.math.Long(xl, xh); - var y = new goog.math.Long(yl, yh); - var ret = x.add(y); - HEAP32[tempDoublePtr>>2] = ret.low_; - HEAP32[tempDoublePtr+4>>2] = ret.high_; - }, subtract: function(xl, xh, yl, yh) { var x = new goog.math.Long(xl, xh); var y = new goog.math.Long(yl, yh); diff --git a/src/modules.js b/src/modules.js index 65b8d437..bda8a605 100644 --- a/src/modules.js +++ b/src/modules.js @@ -374,7 +374,7 @@ var LibraryManager = { load: function() { if (this.library) return; - var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js'].concat(additionalLibraries); + var libraries = ['library.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js'].concat(additionalLibraries); for (var i = 0; i < libraries.length; i++) { eval(processMacros(preprocess(read(libraries[i])))); } diff --git a/src/parseTools.js b/src/parseTools.js index 48274cd5..2664baed 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1724,13 +1724,14 @@ function makeLLVMStruct(values) { } } -function makeStructuralReturn(values) { +function makeStructuralReturn(values, inAsm) { if (USE_TYPED_ARRAYS == 2) { - var i = 0; - return 'return (' + values.slice(1).map(function(value) { - return ASM_JS ? 'asm.setTempRet' + (i++) + '(' + value + ')' + var i = -1; + return 'return ' + asmCoercion(values.slice(1).map(function(value) { + i++; + return ASM_JS ? (inAsm ? 'tempRet' + i + ' = ' + value : 'asm.setTempRet' + i + '(' + value + ')') : 'tempRet' + (i++) + ' = ' + value; - }).concat([values[0]]).join(',') + ')'; + }).concat([values[0]]).join(','), 'i32'); } else { var i = 0; return 'return { ' + values.map(function(value) { @@ -1971,6 +1972,10 @@ function processMathop(item) { return finish(['(i64Math' + (ASM_JS ? '_' : '.') + type + '(' + asmCoercion(low1, 'i32') + ',' + asmCoercion(high1, 'i32') + ',' + asmCoercion(low2, 'i32') + ',' + asmCoercion(high2, 'i32') + (lastArg ? ',' + asmCoercion(+lastArg, 'i32') : '') + '),' + makeGetValue('tempDoublePtr', 0, 'i32') + ')', makeGetValue('tempDoublePtr', Runtime.getNativeTypeSize('i32'), 'i32')]); } + function i64PreciseLib(type) { + Types.preciseI64MathUsed = true; + return finish(['_i64' + type[0].toUpperCase() + type.substr(1) + '(' + low1 + ',' + high1 + ',' + low2 + ',' + high2 + ')', 'tempRet0']); + } switch (op) { // basic integer ops case 'or': { @@ -1985,43 +1990,7 @@ function processMathop(item) { case 'shl': case 'ashr': case 'lshr': { - if (!isNumber(idents[1])) { - return '(Runtime' + (ASM_JS ? '_' : '.') + 'bitshift64(' + idents[0] + '[0], ' + idents[0] + '[1],' + Runtime['BITSHIFT64_' + op.toUpperCase()] + ',' + stripCorrections(idents[1]) + '[0]|0),' + - '[' + makeGetTempDouble(0, 'i32') + ',' + makeGetTempDouble(1, 'i32') + '])'; - } - bits = parseInt(idents[1]); - var ander = Math.pow(2, bits)-1; - if (bits < 32) { - switch (op) { - case 'shl': - return '[' + idents[0] + '[0] << ' + idents[1] + ', ' + - '('+idents[0] + '[1] << ' + idents[1] + ') | ((' + idents[0] + '[0]&(' + ander + '<<' + (32 - bits) + ')) >>> (32-' + idents[1] + '))]'; - case 'ashr': - return '[((('+idents[0] + '[0] >>> ' + idents[1] + ') | ((' + idents[0] + '[1]&' + ander + ')<<' + (32 - bits) + ')) >> 0) >>> 0,' + - '(' + idents[0] + '[1] >> ' + idents[1] + ') >>> 0]'; - case 'lshr': - return '[(('+idents[0] + '[0] >>> ' + idents[1] + ') | ((' + idents[0] + '[1]&' + ander + ')<<' + (32 - bits) + ')) >>> 0,' + - idents[0] + '[1] >>> ' + idents[1] + ']'; - } - } else if (bits == 32) { - switch (op) { - case 'shl': - return '[0, ' + idents[0] + '[0]]'; - case 'ashr': - return '[' + idents[0] + '[1], (' + idents[0] + '[1]|0) < 0 ? ' + ander + ' : 0]'; - case 'lshr': - return '[' + idents[0] + '[1], 0]'; - } - } else { // bits > 32 - switch (op) { - case 'shl': - return '[0, ' + idents[0] + '[0] << ' + (bits - 32) + ']'; - case 'ashr': - return '[(' + idents[0] + '[1] >> ' + (bits - 32) + ') >>> 0, (' + idents[0] + '[1]|0) < 0 ? ' + ander + ' : 0]'; - case 'lshr': - return '[' + idents[0] + '[1] >>> ' + (bits - 32) + ', 0]'; - } - } + throw 'shifts should have been legalized!'; } case 'uitofp': case 'sitofp': return RuntimeGenerator.makeBigInt(low1, high1, op[0] == 'u'); case 'fptoui': case 'fptosi': return finish(splitI64(idents[0], true)); @@ -2059,7 +2028,7 @@ function processMathop(item) { // Dangerous, rounded operations. TODO: Fully emulate case 'add': { if (PRECISE_I64_MATH) { - return i64PreciseOp('add'); + return i64PreciseLib('add'); } else { warnI64_1(); return finish(splitI64(mergeI64(idents[0]) + '+' + mergeI64(idents[1]), true)); @@ -2350,3 +2319,7 @@ function getImplementationType(varInfo) { return varInfo.type; } +function charCode(char) { + return char.charCodeAt(0); +} + diff --git a/src/preamble.js b/src/preamble.js index 7538b19c..2cff440c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -503,34 +503,47 @@ function allocate(slab, types, allocator, ptr) { Module['allocate'] = allocate; function Pointer_stringify(ptr, /* optional */ length) { - var utf8 = new Runtime.UTF8Processor(); - var nullTerminated = typeof(length) == "undefined"; - var ret = ""; - var i = 0; + // Find the length, and check for UTF while doing so + var hasUtf = false; var t; + var i = 0; while (1) { + t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; + if (t >= 128) hasUtf = true; + else if (t == 0 && !length) break; + i++; + if (length && i == length) break; + } + if (!length) length = i; + + var ret = ''; + +#if USE_TYPED_ARRAYS == 2 + if (!hasUtf) { + var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack + var curr; + while (length > 0) { + curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK))); + ret = ret ? ret + curr : curr; + ptr += MAX_CHUNK; + length -= MAX_CHUNK; + } + return ret; + } +#endif + + var utf8 = new Runtime.UTF8Processor(); + for (i = 0; i < length; i++) { #if ASSERTIONS - assert(i < TOTAL_MEMORY); + assert(ptr + i < TOTAL_MEMORY); #endif t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; - if (nullTerminated && t == 0) break; ret += utf8.processCChar(t); - i += 1; - if (!nullTerminated && i == length) break; } return ret; } Module['Pointer_stringify'] = Pointer_stringify; -function Array_stringify(array) { - var ret = ""; - for (var i = 0; i < array.length; i++) { - ret += String.fromCharCode(array[i]); - } - return ret; -} -Module['Array_stringify'] = Array_stringify; - // Memory management var PAGE_SIZE = 4096; @@ -557,7 +570,7 @@ function enlargeMemory() { #if ASM_JS == 0 abort('Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value, (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.'); #else - abort('Cannot enlarge memory arrays in asm.js. Compile with -s TOTAL_MEMORY=X with X higher than the current value.'); + abort('Cannot enlarge memory arrays in asm.js. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value, or (2) set Module.TOTAL_MEMORY before the program runs.'); #endif #else // TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top. diff --git a/src/runtime.js b/src/runtime.js index d5c0fabc..2a26db28 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -122,57 +122,6 @@ var Runtime = { INT_TYPES: set('i1', 'i8', 'i16', 'i32', 'i64'), FLOAT_TYPES: set('float', 'double'), - // Mirrors processMathop's treatment of constants (which we optimize directly) - BITSHIFT64_SHL: 0, - BITSHIFT64_ASHR: 1, - BITSHIFT64_LSHR: 2, - bitshift64: function(low, high, op, bits) { - var ret; - var ander = Math.pow(2, bits)-1; - if (bits < 32) { - switch (op) { - case Runtime.BITSHIFT64_SHL: - ret = [low << bits, (high << bits) | ((low&(ander << (32 - bits))) >>> (32 - bits))]; - break; - case Runtime.BITSHIFT64_ASHR: - ret = [(((low >>> bits ) | ((high&ander) << (32 - bits))) >> 0) >>> 0, (high >> bits) >>> 0]; - break; - case Runtime.BITSHIFT64_LSHR: - ret = [((low >>> bits) | ((high&ander) << (32 - bits))) >>> 0, high >>> bits]; - break; - } - } else if (bits == 32) { - switch (op) { - case Runtime.BITSHIFT64_SHL: - ret = [0, low]; - break; - case Runtime.BITSHIFT64_ASHR: - ret = [high, (high|0) < 0 ? ander : 0]; - break; - case Runtime.BITSHIFT64_LSHR: - ret = [high, 0]; - break; - } - } else { // bits > 32 - switch (op) { - case Runtime.BITSHIFT64_SHL: - ret = [0, low << (bits - 32)]; - break; - case Runtime.BITSHIFT64_ASHR: - ret = [(high >> (bits - 32)) >>> 0, (high|0) < 0 ? ander : 0]; - break; - case Runtime.BITSHIFT64_LSHR: - ret = [high >>> (bits - 32) , 0]; - break; - } - } -#if ASSERTIONS - assert(ret); -#endif - HEAP32[tempDoublePtr>>2] = ret[0]; // cannot use utility functions since we are in runtime itself - HEAP32[tempDoublePtr+4>>2] = ret[1]; - }, - // Imprecise bitops utilities or64: function(x, y) { var l = (x | 0) | (y | 0); diff --git a/src/settings.js b/src/settings.js index 101c403c..97963ac5 100644 --- a/src/settings.js +++ b/src/settings.js @@ -163,6 +163,8 @@ var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js). // emscripten_run_script("Runtime.debug = ...;"); var SOCKET_DEBUG = 0; // Log out socket/network data transfer. +var OPENAL_DEBUG = 0; // Print out debugging information from our OpenAL implementation. + var GL_DEBUG = 0; // Print out all calls into WebGL. As with LIBRARY_DEBUG, you can set a runtime // option, in this case GL.debug. var GL_TESTING = 0; // When enabled, sets preserveDrawingBuffer in the context, to allow tests to work (but adds overhead) @@ -224,19 +226,22 @@ var NAMED_GLOBALS = 0; // If 1, we use global variables for globals. Otherwise // they are referred to by a base plus an offset (called an indexed global), // saving global variables but adding runtime overhead. -var EXPORT_ALL = 0; // If true, we export all the symbols var EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported. These functions are kept alive // through LLVM dead code elimination, and also made accessible outside of // the generated code even after running closure compiler (on "Module"). // Note the necessary prefix of "_". +var EXPORT_ALL = 0; // If true, we export all the symbols +var EXPORT_BINDINGS = 0; // Export all bindings generator functions (prefixed with emscripten_bind_). This + // is necessary to use the bindings generator with asm.js -var DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = ['memcpy', 'memset', 'malloc', 'free', '$Browser']; // JS library functions (C functions implemented in JS) - // that we include by default. If you want to make sure - // something is included by the JS compiler, add it here. - // For example, if you do not use some emscripten_* - // C API call from C, but you want to call it from JS, - // add it here (and in EXPORTED FUNCTIONS with prefix - // "_", for closure). +// JS library functions (C functions implemented in JS) +// that we include by default. If you want to make sure +// something is included by the JS compiler, add it here. +// For example, if you do not use some emscripten_* +// C API call from C, but you want to call it from JS, +// add it here (and in EXPORTED FUNCTIONS with prefix +// "_", for closure). +var DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = ['memcpy', 'memset', 'malloc', 'free', 'strlen', '$Browser']; var LIBRARY_DEPS_TO_AUTOEXPORT = ['memcpy']; // This list is also used to determine // auto-exporting of library dependencies (i.e., functions that @@ -337,8 +342,14 @@ var PGO = 0; // Enables profile-guided optimization in the form of runtime check // can pass to DEAD_FUNCTIONS (you can also emit the list manually by // calling PGOMonitor.dump()); var DEAD_FUNCTIONS = []; // A list of functions that no code will be emitted for, and - // a runtime abort will happen if they are called + // a runtime abort will happen if they are called. If + // such a function is an unresolved reference, that is not + // considered an error. // TODO: options to lazily load such functions +var UNRESOLVED_AS_DEAD = 0; // Handle all unresolved functions as if they were in the + // list of dead functions. This is a quick way to turn + // all unresolved references into runtime aborts (and not + // get compile-time warnings or errors on them). var EXPLICIT_ZEXT = 0; // If 1, generate an explicit conversion of zext i1 to i32, using ?: diff --git a/src/utility.js b/src/utility.js index 8db37c61..19444675 100644 --- a/src/utility.js +++ b/src/utility.js @@ -267,6 +267,15 @@ function set() { } var unset = keys; +function numberedSet() { + var args = typeof arguments[0] === 'object' ? arguments[0] : arguments; + var ret = {}; + for (var i = 0; i < args.length; i++) { + ret[args[i]] = i; + } + return ret; +} + function setSub(x, y) { var ret = set(keys(x)); for (yy in y) { diff --git a/system/include/AL/al.h b/system/include/AL/al.h new file mode 100644 index 00000000..d7234e32 --- /dev/null +++ b/system/include/AL/al.h @@ -0,0 +1,172 @@ +#ifndef OPENAL_AL_H__ +#define OPENAL_AL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AL_BITS 0x2002 +#define AL_BUFFER 0x1009 +#define AL_BUFFERS_PROCESSED 0x1016 +#define AL_BUFFERS_QUEUED 0x1015 +#define AL_BYTE_OFFSET 0x1026 +#define AL_CHANNELS 0x2003 +#define AL_CONE_INNER_ANGLE 0x1001 +#define AL_CONE_OUTER_ANGLE 0x1002 +#define AL_CONE_OUTER_GAIN 0x1022 +#define AL_DIRECTION 0x1005 +#define AL_DISTANCE_MODEL 0xD000 +#define AL_DOPPLER_FACTOR 0xC000 +#define AL_DOPPLER_VELOCITY 0xC001 +#define AL_EXPONENT_DISTANCE 0xD005 +#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 +#define AL_EXTENSIONS 0xB004 +#define AL_FALSE 0 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_STEREO16 0x1103 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FREQUENCY 0x2001 +#define AL_GAIN 0x100A +#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION +#define AL_ILLEGAL_ENUM AL_INVALID_ENUM +#define AL_INITIAL 0x1011 +#define AL_INVALID (-1) +#define AL_INVALID_ENUM 0xA002 +#define AL_INVALID_NAME 0xA001 +#define AL_INVALID_OPERATION 0xA004 +#define AL_INVALID_VALUE 0xA003 +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 +#define AL_LINEAR_DISTANCE 0xD003 +#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 +#define AL_LOOPING 0x1007 +#define AL_MAX_DISTANCE 0x1023 +#define AL_MAX_GAIN 0x100E +#define AL_MIN_GAIN 0x100D +#define AL_NONE 0 +#define AL_NO_ERROR 0 +#define AL_ORIENTATION 0x100F +#define AL_OUT_OF_MEMORY 0xA005 +#define AL_PAUSED 0x1013 +#define AL_PENDING 0x2011 +#define AL_PITCH 0x1003 +#define AL_PLAYING 0x1012 +#define AL_POSITION 0x1004 +#define AL_PROCESSED 0x2012 +#define AL_REFERENCE_DISTANCE 0x1020 +#define AL_RENDERER 0xB003 +#define AL_ROLLOFF_FACTOR 0x1021 +#define AL_SAMPLE_OFFSET 0x1025 +#define AL_SEC_OFFSET 0x1024 +#define AL_SIZE 0x2004 +#define AL_SOURCE_RELATIVE 0x202 +#define AL_SOURCE_STATE 0x1010 +#define AL_SOURCE_TYPE 0x1027 +#define AL_SPEED_OF_SOUND 0xC003 +#define AL_STATIC 0x1028 +#define AL_STOPPED 0x1014 +#define AL_STREAMING 0x1029 +#define AL_TRUE 1 +#define AL_UNDETERMINED 0x1030 +#define AL_UNUSED 0x2010 +#define AL_VELOCITY 0x1006 +#define AL_VENDOR 0xB001 +#define AL_VERSION 0xB002 +#define AL_VERSION_1_0 +#define AL_VERSION_1_1 +#define OPENAL + +typedef char ALboolean; +typedef char ALchar; +typedef double ALdouble; +typedef float ALfloat; +typedef int ALenum; +typedef int ALint; +typedef int ALsizei; +typedef short ALshort; +typedef signed char ALbyte; +typedef unsigned char ALubyte; +typedef unsigned int ALuint; +typedef unsigned short ALushort; +typedef void ALvoid; + +extern ALboolean alGetBoolean(ALenum param); +extern ALboolean alIsBuffer(ALuint buffer); +extern ALboolean alIsEnabled(ALenum capability); +extern ALboolean alIsExtensionPresent(const ALchar *extname); +extern ALboolean alIsSource(ALuint source); +extern ALdouble alGetDouble(ALenum param); +extern ALenum alGetEnumValue(const ALchar *ename); +extern ALenum alGetError(); +extern ALfloat alGetFloat(ALenum param); +extern ALint alGetInteger(ALenum param); +extern const ALchar *alGetString(ALenum param); +extern void *alGetProcAddress(const ALchar *fname); +extern void alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +extern void alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); +extern void alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); +extern void alBufferf(ALuint buffer, ALenum param, ALfloat value); +extern void alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); +extern void alBufferi(ALuint buffer, ALenum param, ALint value); +extern void alBufferiv(ALuint buffer, ALenum param, const ALint *values); +extern void alDeleteBuffers(ALsizei n, const ALuint *buffers); +extern void alDeleteSources(ALsizei n, const ALuint *sources); +extern void alDisable(ALenum capability); +extern void alDistanceModel(ALenum distanceModel); +extern void alDopplerFactor(ALfloat value); +extern void alDopplerVelocity(ALfloat value); +extern void alEnable(ALenum capability); +extern void alGenBuffers(ALsizei n, ALuint *buffers); +extern void alGenSources(ALsizei n, ALuint *sources); +extern void alGetBooleanv(ALenum param, ALboolean *values); +extern void alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +extern void alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); +extern void alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); +extern void alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); +extern void alGetBufferi(ALuint buffer, ALenum param, ALint *value); +extern void alGetBufferiv(ALuint buffer, ALenum param, ALint *values); +extern void alGetDoublev(ALenum param, ALdouble *values); +extern void alGetFloatv(ALenum param, ALfloat *values); +extern void alGetIntegerv(ALenum param, ALint *values); +extern void alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +extern void alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); +extern void alGetListenerf(ALenum param, ALfloat *value); +extern void alGetListenerfv(ALenum param, ALfloat *values); +extern void alGetListeneri(ALenum param, ALint *value); +extern void alGetListeneriv(ALenum param, ALint *values); +extern void alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +extern void alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); +extern void alGetSourcef(ALuint source, ALenum param, ALfloat *value); +extern void alGetSourcefv(ALuint source, ALenum param, ALfloat *values); +extern void alGetSourcei(ALuint source, ALenum param, ALint *value); +extern void alGetSourceiv(ALuint source, ALenum param, ALint *values); +extern void alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +extern void alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); +extern void alListenerf(ALenum param, ALfloat value); +extern void alListenerfv(ALenum param, const ALfloat *values); +extern void alListeneri(ALenum param, ALint value); +extern void alListeneriv(ALenum param, const ALint *values); +extern void alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +extern void alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); +extern void alSourcePause(ALuint source); +extern void alSourcePausev(ALsizei n, const ALuint *sources); +extern void alSourcePlay(ALuint source); +extern void alSourcePlayv(ALsizei n, const ALuint *sources); +extern void alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); +extern void alSourceRewind(ALuint source); +extern void alSourceRewindv(ALsizei n, const ALuint *sources); +extern void alSourceStop(ALuint source); +extern void alSourceStopv(ALsizei n, const ALuint *sources); +extern void alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); +extern void alSourcef(ALuint source, ALenum param, ALfloat value); +extern void alSourcefv(ALuint source, ALenum param, const ALfloat *values); +extern void alSourcei(ALuint source, ALenum param, ALint value); +extern void alSourceiv(ALuint source, ALenum param, const ALint *values); +extern void alSpeedOfSound(ALfloat value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/AL/alc.h b/system/include/AL/alc.h new file mode 100644 index 00000000..6ff7cb9b --- /dev/null +++ b/system/include/AL/alc.h @@ -0,0 +1,84 @@ +#ifndef OPENAL_ALC_H__ +#define OPENAL_ALC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_ALL_ATTRIBUTES 0x1003 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +#define ALC_CAPTURE_SAMPLES 0x312 +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +#define ALC_DEVICE_SPECIFIER 0x1005 +#define ALC_ENUMERATE_ALL_EXT 1 +#define ALC_EXTENSIONS 0x1006 +#define ALC_EXT_CAPTURE 1 +#define ALC_FALSE 0 +#define ALC_FREQUENCY 0x1007 +#define ALC_INVALID 0 +#define ALC_INVALID_CONTEXT 0xA002 +#define ALC_INVALID_DEVICE 0xA001 +#define ALC_INVALID_ENUM 0xA003 +#define ALC_INVALID_VALUE 0xA004 +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 +#define ALC_MONO_SOURCES 0x1010 +#define ALC_NO_ERROR 0 +#define ALC_OUT_OF_MEMORY 0xA005 +#define ALC_REFRESH 0x1008 +#define ALC_STEREO_SOURCES 0x1011 +#define ALC_SYNC 0x1009 +#define ALC_TRUE 1 +#define ALC_VERSION_0_1 1 +#define AL_ALC_H + +struct ALCcontext_struct; +struct ALCdevice_struct; +typedef char ALCboolean; +typedef char ALCchar; +typedef double ALCdouble; +typedef float ALCfloat; +typedef int ALCenum; +typedef int ALCint; +typedef int ALCsizei; +typedef short ALCshort; +typedef signed char ALCbyte; +typedef struct ALCcontext_struct ALCcontext; +typedef struct ALCdevice_struct ALCdevice; +typedef unsigned char ALCubyte; +typedef unsigned int ALCuint; +typedef unsigned short ALCushort; +typedef void ALCvoid; + +extern ALCboolean alcCaptureCloseDevice(ALCdevice *device); +extern ALCboolean alcCloseDevice(ALCdevice *device); +extern ALCboolean alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); +extern ALCboolean alcMakeContextCurrent(ALCcontext *context); +extern ALCcontext *alcCreateContext(ALCdevice *device, const ALCint *attrlist); +extern ALCcontext *alcGetCurrentContext(); +extern ALCdevice *alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); +extern ALCdevice *alcGetContextsDevice(ALCcontext *context); +extern ALCdevice *alcOpenDevice(const ALCchar *devicename); +extern ALCenum alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); +extern ALCenum alcGetError(ALCdevice *device); +extern const ALCchar *alcGetString(ALCdevice *device, ALCenum param); +extern void *alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); +extern void alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +extern void alcCaptureStart(ALCdevice *device); +extern void alcCaptureStop(ALCdevice *device); +extern void alcDestroyContext(ALCcontext *context); +extern void alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); +extern void alcProcessContext(ALCcontext *context); +extern void alcSuspendContext(ALCcontext *context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/system/include/libc/ctype.h b/system/include/libc/ctype.h index 26d3c6ce..383a8db1 100644 --- a/system/include/libc/ctype.h +++ b/system/include/libc/ctype.h @@ -72,11 +72,14 @@ _CONST #define isgraph(__c) (__ctype_lookup(__c)&(CTYPE__P|CTYPE__U|CTYPE__L|CTYPE__N)) #define iscntrl(__c) (__ctype_lookup(__c)&CTYPE__C) +/* XXX: EMSCRIPTEN: We alter the names of __typeof__ declarations to + reduce the chance of them conflicting when expanded */ + #if defined(__GNUC__) && \ (!defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901L) #define isblank(__c) \ - __extension__ ({ __typeof__ (__c) __x = (__c); \ - (__ctype_lookup(__x)&_B) || (int) (__x) == '\t';}) + __extension__ ({ __typeof__ (__c) __ctb_x = (__c); \ + (__ctype_lookup(__ctb_x)&_B) || (int) (__ctb_x) == '\t';}) #endif @@ -86,20 +89,20 @@ _CONST # if defined(__GNUC__) # if !defined (_MB_EXTENDED_CHARSETS_ISO) && !defined (_MB_EXTENDED_CHARSETS_WINDOWS) # define toupper(__c) \ - __extension__ ({ __typeof__ (__c) __x = (__c); \ - islower (__x) ? (int) __x - 'a' + 'A' : (int) __x;}) + __extension__ ({ __typeof__ (__c) __cttu_x = (__c); \ + islower (__cttu_x) ? (int) __cttu_x - 'a' + 'A' : (int) __cttu_x;}) # define tolower(__c) \ - __extension__ ({ __typeof__ (__c) __x = (__c); \ - isupper (__x) ? (int) __x - 'A' + 'a' : (int) __x;}) + __extension__ ({ __typeof__ (__c) __cttl_x = (__c); \ + isupper (__cttl_x) ? (int) __cttl_x - 'A' + 'a' : (int) __cttl_x;}) # else /* _MB_EXTENDED_CHARSETS* */ /* Allow a gcc warning if the user passed 'char', but defer to the function. */ # define toupper(__c) \ - __extension__ ({ __typeof__ (__c) __x = (__c); \ - (void) __ctype_ptr__[__x]; (toupper) (__x);}) + __extension__ ({ __typeof__ (__c) __cttu_x = (__c); \ + (void) __ctype_ptr__[__cttu_x]; (toupper) (__cttu_x);}) # define tolower(__c) \ - __extension__ ({ __typeof__ (__c) __x = (__c); \ - (void) __ctype_ptr__[__x]; (tolower) (__x);}) + __extension__ ({ __typeof__ (__c) __cttl_x = (__c); \ + (void) __ctype_ptr__[__cttl_x]; (tolower) (__cttl_x);}) # endif /* _MB_EXTENDED_CHARSETS* */ # endif /* __GNUC__ */ #endif /* !__cplusplus */ diff --git a/system/include/libc/math.h b/system/include/libc/math.h index d963c6c8..e2f8cdef 100644 --- a/system/include/libc/math.h +++ b/system/include/libc/math.h @@ -210,25 +210,28 @@ extern int __signbitd (double x); ((sizeof(__x) == sizeof(float)) ? __signbitf(__x) : \ __signbitd(__x)) +/* XXX: EMSCRIPTEN: We alter the names of __typeof__ declarations to + reduce the chance of them conflicting when expanded */ + #define isgreater(x,y) \ - (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x,__y) && (__x > __y);})) + (__extension__ ({__typeof__(x) __isg_x = (x); __typeof__(y) __isg_y = (y); \ + !isunordered(__isg_x,__isg_y) && (__isg_x > __isg_y);})) #define isgreaterequal(x,y) \ - (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x,__y) && (__x >= __y);})) + (__extension__ ({__typeof__(x) __isge_x = (x); __typeof__(y) __isge_y = (y); \ + !isunordered(__isge_x,__isge_y) && (__isge_x >= __isge_y);})) #define isless(x,y) \ - (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x,__y) && (__x < __y);})) + (__extension__ ({__typeof__(x) __isl_x = (x); __typeof__(y) __isl_y = (y); \ + !isunordered(__isl_x,__isl_y) && (__isl_x < __isl_y);})) #define islessequal(x,y) \ - (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x,__y) && (__x <= __y);})) + (__extension__ ({__typeof__(x) __isle_x = (x); __typeof__(y) __isle_y = (y); \ + !isunordered(__isle_x,__isle_y) && (__isle_x <= __isle_y);})) #define islessgreater(x,y) \ - (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ - !isunordered(__x,__y) && (__x < __y || __x > __y);})) + (__extension__ ({__typeof__(x) __islg_x = (x); __typeof__(y) __islg_y = (y); \ + !isunordered(__islg_x,__islg_y) && (__islg_x < __islg_y || __islg_x > __islg_y);})) #define isunordered(a,b) \ - (__extension__ ({__typeof__(a) __a = (a); __typeof__(b) __b = (b); \ - fpclassify(__a) == FP_NAN || fpclassify(__b) == FP_NAN;})) + (__extension__ ({__typeof__(a) __isu_a = (a); __typeof__(b) __isu_b = (b); \ + fpclassify(__isu_a) == FP_NAN || fpclassify(__isu_b) == FP_NAN;})) /* Non ANSI double precision functions. */ diff --git a/tests/cases/alignedunaligned.ll b/tests/cases/alignedunaligned.ll index 9faa87ef..f4e0535a 100644 --- a/tests/cases/alignedunaligned.ll +++ b/tests/cases/alignedunaligned.ll @@ -15,9 +15,7 @@ entry: %saved_stack = alloca i8* ; [#uses=2 type=i8**] %cleanup.dest.slot = alloca i32 ; [#uses=1 type=i32*] store i32 0, i32* %retval - call void @llvm.dbg.declare(metadata !{i8** %str}, metadata !12), !dbg !16 ; [debug line = 6:19] [debug variable = str] store i8* getelementptr inbounds ([13 x i8]* @.str, i32 0, i32 0), i8** %str, align 4, !dbg !17 ; [debug line = 6:39] - call void @llvm.dbg.declare(metadata !{i32* %len}, metadata !18), !dbg !19 ; [debug line = 7:17] [debug variable = len] %0 = load i8** %str, align 4, !dbg !20 ; [#uses=1 type=i8*] [debug line = 7:23] %call = call i32 @strlen(i8* %0), !dbg !20 ; [#uses=1 type=i32] [debug line = 7:23] store i32 %call, i32* %len, align 4, !dbg !20 ; [debug line = 7:23] @@ -26,7 +24,6 @@ entry: %2 = call i8* @llvm.stacksave(), !dbg !21 ; [#uses=1 type=i8*] [debug line = 8:29] store i8* %2, i8** %saved_stack, !dbg !21 ; [debug line = 8:29] %vla = alloca i8, i32 %add, align 1, !dbg !21 ; [#uses=93 type=i8*] [debug line = 8:29] - call void @llvm.dbg.declare(metadata !{i8* %vla}, metadata !22), !dbg !26 ; [debug line = 8:18] [debug variable = curr] %3 = load i32* %len, align 4, !dbg !27 ; [#uses=1 type=i32] [debug line = 13:13] call void @llvm.memset.p0i8.i32(i8* %vla, i8 46, i32 %3, i32 4, i1 false), !dbg !27 ; [debug line = 13:13] %4 = load i32* %len, align 4, !dbg !27 ; [#uses=1 type=i32] [debug line = 13:13] @@ -210,9 +207,6 @@ entry: ret i32 %63, !dbg !122 ; [debug line = 40:11] } -; [#uses=3] -declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone - ; [#uses=1] declare i32 @strlen(i8*) diff --git a/tests/cases/breakinthemiddle3.ll b/tests/cases/breakinthemiddle3.ll new file mode 100644 index 00000000..e9173965 --- /dev/null +++ b/tests/cases/breakinthemiddle3.ll @@ -0,0 +1,26 @@ +@.str = private constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1] + +define linkonce_odr i32 @main() align 2 { + %333 = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0] + %199 = trunc i8 1 to i1 ; [#uses=1] + switch i32 %333, label %label999 [ + i32 1000, label %label995 + ] ; switch should ignore all code after it in the block + ; No predecessors! + %a472 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + cleanup + %a473 = extractvalue { i8*, i32 } %a472, 0 + %a474 = extractvalue { i8*, i32 } %a472, 1 + br label %label999 + +label995: + %333b = call i32 @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0] + br label %label999 + +label999: ; preds = %555 + ret i32 0 +} + +declare i32 @printf(i8*) +declare i32 @__gxx_personality_v0(...) + diff --git a/tests/cases/callundef.ll b/tests/cases/callundef.ll new file mode 100644 index 00000000..a540a08c --- /dev/null +++ b/tests/cases/callundef.ll @@ -0,0 +1,18 @@ +; ModuleID = 'tests/hello_world.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*] + +; [#uses=0] +define i32 @main() { +entry: + %retval = alloca i32, align 4 ; [#uses=1 type=i32*] + store i32 0, i32* %retval + %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32] + call void undef(i32 55) + ret i32 1 +} + +; [#uses=1] +declare i32 @printf(i8*, ...) diff --git a/tests/cases/phicubed.ll b/tests/cases/phicubed.ll index 4f0611ec..a0799997 100644 --- a/tests/cases/phicubed.ll +++ b/tests/cases/phicubed.ll @@ -12,25 +12,16 @@ entry: %a = alloca %struct.worker_args, align 4 ; [#uses=3 type=%struct.worker_args*] %b = alloca %struct.worker_args, align 4 ; [#uses=4 type=%struct.worker_args*] %chunk = alloca [10 x %struct.worker_args], align 4 ; [#uses=30 type=[10 x %struct.worker_args]*] - call void @llvm.dbg.declare(metadata !{%struct.worker_args* %a}, metadata !12), !dbg !23 ; [debug line = 9:25] [debug variable = a] - call void @llvm.dbg.declare(metadata !{%struct.worker_args* %b}, metadata !24), !dbg !25 ; [debug line = 10:25] [debug variable = b] %value = getelementptr inbounds %struct.worker_args* %a, i32 0, i32 0, !dbg !26 ; [#uses=1 type=i32*] [debug line = 11:13] store i32 60, i32* %value, align 4, !dbg !26 ; [debug line = 11:13] call void @emscripten_autodebug_i32(i32 16, i32 60) %next = getelementptr inbounds %struct.worker_args* %a, i32 0, i32 1, !dbg !27 ; [#uses=1 type=%struct.worker_args**] [debug line = 12:13] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %b}, i64 0, metadata !24), !dbg !27 ; [debug line = 12:13] [debug variable = b] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %b}, i64 0, metadata !24), !dbg !27 ; [debug line = 12:13] [debug variable = b] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %b}, i64 0, metadata !24), !dbg !27 ; [debug line = 12:13] [debug variable = b] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %b}, i64 0, metadata !24), !dbg !27 ; [debug line = 12:13] [debug variable = b] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %b}, i64 0, metadata !24), !dbg !27 ; [debug line = 12:13] [debug variable = b] store %struct.worker_args* %b, %struct.worker_args** %next, align 4, !dbg !27 ; [debug line = 12:13] %value1 = getelementptr inbounds %struct.worker_args* %b, i32 0, i32 0, !dbg !28 ; [#uses=1 type=i32*] [debug line = 13:13] store i32 900, i32* %value1, align 4, !dbg !28 ; [debug line = 13:13] call void @emscripten_autodebug_i32(i32 26, i32 900) %next2 = getelementptr inbounds %struct.worker_args* %b, i32 0, i32 1, !dbg !29 ; [#uses=1 type=%struct.worker_args**] [debug line = 14:13] store %struct.worker_args* null, %struct.worker_args** %next2, align 4, !dbg !29 ; [debug line = 14:13] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %a}, i64 0, metadata !30), !dbg !31 ; [debug line = 15:32] [debug variable = c] - call void @llvm.dbg.value(metadata !2, i64 0, metadata !32), !dbg !33 ; [debug line = 16:26] [debug variable = total] br label %while.body, !dbg !34 ; [debug line = 17:13] for.cond.preheader: ; preds = %while.body @@ -40,70 +31,60 @@ for.cond.preheader: ; preds = %while.body %arrayidx7 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 0, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7, %struct.worker_args** %next9, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.1 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 1, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 10, i32* %value5.1, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 43, i32 10) %arrayidx7.1 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 2, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.1 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 1, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.1, %struct.worker_args** %next9.1, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.2 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 2, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 20, i32* %value5.2, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 50, i32 20) %arrayidx7.2 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 3, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.2 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 2, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.2, %struct.worker_args** %next9.2, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.3 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 3, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 30, i32* %value5.3, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 57, i32 30) %arrayidx7.3 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 4, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.3 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 3, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.3, %struct.worker_args** %next9.3, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.4 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 4, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 40, i32* %value5.4, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 64, i32 40) %arrayidx7.4 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 5, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.4 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 4, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.4, %struct.worker_args** %next9.4, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.5 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 5, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 50, i32* %value5.5, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 71, i32 50) %arrayidx7.5 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 6, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.5 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 5, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.5, %struct.worker_args** %next9.5, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.6 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 6, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 60, i32* %value5.6, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 78, i32 60) %arrayidx7.6 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 7, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.6 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 6, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.6, %struct.worker_args** %next9.6, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.7 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 7, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 70, i32* %value5.7, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 85, i32 70) %arrayidx7.7 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 8, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.7 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 7, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.7, %struct.worker_args** %next9.7, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value5.8 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 8, i32 0, !dbg !35 ; [#uses=1 type=i32*] [debug line = 25:15] store i32 80, i32* %value5.8, align 4, !dbg !35 ; [debug line = 25:15] call void @emscripten_autodebug_i32(i32 92, i32 80) %arrayidx7.8 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 9, !dbg !38 ; [#uses=1 type=%struct.worker_args*] [debug line = 26:15] %next9.8 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 8, i32 1, !dbg !38 ; [#uses=1 type=%struct.worker_args**] [debug line = 26:15] store %struct.worker_args* %arrayidx7.8, %struct.worker_args** %next9.8, align 4, !dbg !38 ; [debug line = 26:15] - call void @llvm.dbg.value(metadata !39, i64 0, metadata !40), !dbg !41 ; [debug line = 24:36] [debug variable = i] %value11 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 9, i32 0, !dbg !42 ; [#uses=1 type=i32*] [debug line = 28:13] store i32 90, i32* %value11, align 4, !dbg !42 ; [debug line = 28:13] call void @emscripten_autodebug_i32(i32 99, i32 90) %arrayidx12 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 0, !dbg !43 ; [#uses=3 type=%struct.worker_args*] [debug line = 29:13] %next14 = getelementptr inbounds [10 x %struct.worker_args]* %chunk, i32 0, i32 9, i32 1, !dbg !43 ; [#uses=1 type=%struct.worker_args**] [debug line = 29:13] store %struct.worker_args* %arrayidx12, %struct.worker_args** %next14, align 4, !dbg !43 ; [debug line = 29:13] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %arrayidx12}, i64 0, metadata !30), !dbg !44 ; [debug line = 31:13] [debug variable = c] br label %do.body, !dbg !45 ; [debug line = 32:13] while.body: ; preds = %while.body.while.body_crit_edge, %entry @@ -114,8 +95,6 @@ while.body: ; preds = %while.body.while.bo %1 = load i32* %value3, align 4, !dbg !46 ; [#uses=2 type=i32] [debug line = 18:15] call void @emscripten_autodebug_i32(i32 112, i32 %1) %add = add nsw i32 %1, %total.02, !dbg !46 ; [#uses=2 type=i32] [debug line = 18:15] - call void @llvm.dbg.value(metadata !{i32 %add}, i64 0, metadata !32), !dbg !46 ; [debug line = 18:15] [debug variable = total] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %0}, i64 0, metadata !30), !dbg !48 ; [debug line = 19:15] [debug variable = c] %tobool = icmp eq %struct.worker_args* %0, null, !dbg !34 ; [#uses=1 type=i1] [debug line = 17:13] br i1 %tobool, label %for.cond.preheader, label %while.body.while.body_crit_edge, !dbg !34 ; [debug line = 17:13] @@ -131,10 +110,8 @@ do.body: ; preds = %do.body, %for.cond. %2 = load i32* %value15, align 4, !dbg !49 ; [#uses=2 type=i32] [debug line = 33:15] call void @emscripten_autodebug_i32(i32 129, i32 %2) %add16 = add nsw i32 %2, %total.1, !dbg !49 ; [#uses=2 type=i32] [debug line = 33:15] - call void @llvm.dbg.value(metadata !{i32 %add16}, i64 0, metadata !32), !dbg !49 ; [debug line = 33:15] [debug variable = total] %next17 = getelementptr inbounds %struct.worker_args* %c.1, i32 0, i32 1, !dbg !51 ; [#uses=1 type=%struct.worker_args**] [debug line = 34:15] %3 = load %struct.worker_args** %next17, align 4, !dbg !51 ; [#uses=2 type=%struct.worker_args*] [debug line = 34:15] - call void @llvm.dbg.value(metadata !{%struct.worker_args* %3}, i64 0, metadata !30), !dbg !51 ; [debug line = 34:15] [debug variable = c] %cmp19 = icmp eq %struct.worker_args* %3, %arrayidx12, !dbg !52 ; [#uses=1 type=i1] [debug line = 35:13] br i1 %cmp19, label %do.end, label %do.body, !dbg !52 ; [debug line = 35:13] @@ -143,15 +120,9 @@ do.end: ; preds = %do.body ret i32 0, !dbg !54 ; [debug line = 40:13] } -; [#uses=2] -declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone - ; [#uses=7] declare i32 @printf(i8* nocapture, ...) nounwind -; [#uses=21] -declare void @llvm.dbg.value(metadata, i64, metadata) nounwind readnone - ; [#uses=0] define void @emscripten_autodebug_i64(i32 %line, i64 %value) { entry: diff --git a/tests/cases/storestruct.ll b/tests/cases/storestruct.ll index 5bd9224e..a5b7483b 100644 --- a/tests/cases/storestruct.ll +++ b/tests/cases/storestruct.ll @@ -15,8 +15,6 @@ entry: %x = alloca %struct.X, align 4 ; [#uses=2] %y = alloca %struct.X, align 4 ; [#uses=2] store i32 0, i32* %retval - call void @llvm.dbg.declare(metadata !{%struct.X* %x}, metadata !6), !dbg !13 - call void @llvm.dbg.declare(metadata !{%struct.X* %y}, metadata !14), !dbg !15 %a = getelementptr inbounds %struct.X* %x, i32 0, i32 0, !dbg !16 ; [#uses=1] store i32 5, i32* %a, align 4, !dbg !16 %b = getelementptr inbounds %struct.X* %x, i32 0, i32 1, !dbg !17 ; [#uses=1] @@ -54,9 +52,6 @@ entry: ret i32 0, !dbg !19 } -; [#uses=2] -declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone - ; [#uses=1] declare i32 @printf(i8*, ...) diff --git a/tests/cases/unannotated.ll b/tests/cases/unannotated__noasm.ll index d87b2e54..d87b2e54 100644 --- a/tests/cases/unannotated.ll +++ b/tests/cases/unannotated__noasm.ll diff --git a/tests/cases/unannotated.txt b/tests/cases/unannotated__noasm.txt index 9daeafb9..9daeafb9 100644 --- a/tests/cases/unannotated.txt +++ b/tests/cases/unannotated__noasm.txt diff --git a/tests/gl_ps_strides.c b/tests/gl_ps_strides.c new file mode 100644 index 00000000..d88f5d0b --- /dev/null +++ b/tests/gl_ps_strides.c @@ -0,0 +1,241 @@ +/******************************************************************* + * * + * Using SDL With OpenGL * + * * + * Tutorial by Kyle Foley (sdw) * + * * + * http://gpwiki.org/index.php/SDL:Tutorials:Using_SDL_with_OpenGL * + * * + *******************************************************************/ + +/* +THIS WORK, INCLUDING THE SOURCE CODE, DOCUMENTATION +AND RELATED MEDIA AND DATA, IS PLACED INTO THE PUBLIC DOMAIN. + +THE ORIGINAL AUTHOR IS KYLE FOLEY. + +THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY +OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF +MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, +ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE +RESULTING FROM THE USE, MODIFICATION, OR +REDISTRIBUTION OF THIS SOFTWARE. +*/ + +#if !EMSCRIPTEN +#define USE_GLEW 1 +#endif + +#if USE_GLEW +#include "GL/glew.h" +#endif + +#include "SDL/SDL.h" +#include "SDL/SDL_image.h" +#if !USE_GLEW +#include "SDL/SDL_opengl.h" +#endif + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +void shaders() { +#if USE_GLEW + glewInit(); +#endif + + GLint ok; + + const char *vertexShader = "void main(void) \n" + "{ \n" + " gl_Position = ftransform(); \n" + " gl_TexCoord[0] = gl_MultiTexCoord0; \n" + " gl_FrontColor = gl_Color; \n" + "} \n"; + const char *fragmentShader = "uniform sampler2D tex0; \n" + "void main(void) \n" + "{ \n" + " gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy); \n" + "} \n"; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &vertexShader, NULL); + glCompileShader(vs); + glGetShaderiv(vs, GL_COMPILE_STATUS, &ok); + assert(ok); + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, &fragmentShader, NULL); + glCompileShader(fs); + glGetShaderiv(fs, GL_COMPILE_STATUS, &ok); + assert(ok); + + GLuint program = glCreateProgram(); + + glAttachShader(program, vs); + glAttachShader(program, fs); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &ok); + assert(ok); + assert(glIsProgram(program)); + assert(!glIsProgram(0)); + assert(!glIsProgram(program+1)); // a number that can't be a real shader + + glUseProgram(program); + + { + // Also, check getting the error log + const char *fakeVertexShader = "atbute ve4 blarg; ### AAA\n"; + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &fakeVertexShader, NULL); + glCompileShader(vs); + glGetShaderiv(vs, GL_COMPILE_STATUS, &ok); + assert(!ok); + GLint infoLen = 0; + glGetShaderiv(vs, GL_INFO_LOG_LENGTH, &infoLen); + assert(infoLen > 1); + } +} + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen; + + // Slightly different SDL initialization + if ( SDL_Init(SDL_INIT_VIDEO) != 0 ) { + printf("Unable to initialize SDL: %s\n", SDL_GetError()); + return 1; + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // *new* + + screen = SDL_SetVideoMode( 640, 480, 16, SDL_OPENGL ); // *changed* + if ( !screen ) { + printf("Unable to set video mode: %s\n", SDL_GetError()); + return 1; + } + + // Set the OpenGL state after creating the context with SDL_SetVideoMode + + glClearColor( 0, 0, 0, 0 ); + +#if !EMSCRIPTEN + glEnable( GL_TEXTURE_2D ); // Need this to display a texture XXX unnecessary in OpenGL ES 2.0/WebGL +#endif + + glViewport( 0, 0, 640, 480 ); + + glMatrixMode( GL_PROJECTION ); + GLfloat matrixData[] = { 2.0/640, 0, 0, 0, + 0, -2.0/480, 0, 0, + 0, 0, -1, 0, + -1, 1, 0, 1 }; + glLoadMatrixf(matrixData); // test loadmatrix + + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + + // Load the OpenGL texture + + GLuint texture; // Texture object handle + SDL_Surface *surface; // Gives us the information to make the texture + + if ( (surface = IMG_Load("screenshot.png")) ) { + + // Check that the image's width is a power of 2 + if ( (surface->w & (surface->w - 1)) != 0 ) { + printf("warning: image.bmp's width is not a power of 2\n"); + } + + // Also check if the height is a power of 2 + if ( (surface->h & (surface->h - 1)) != 0 ) { + printf("warning: image.bmp's height is not a power of 2\n"); + } + + // Have OpenGL generate a texture object handle for us + glGenTextures( 1, &texture ); + + // Bind the texture object + glBindTexture( GL_TEXTURE_2D, texture ); + + // Set the texture's stretching properties + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + //SDL_LockSurface(surface); + + // Add some greyness + memset(surface->pixels, 0x66, surface->w*surface->h); + + // Edit the texture object's image data using the information SDL_Surface gives us + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, + GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels ); + + //SDL_UnlockSurface(surface); + } + else { + printf("SDL could not load image.bmp: %s\n", SDL_GetError()); + SDL_Quit(); + return 1; + } + + // Free the SDL_Surface only if it was successfully created + if ( surface ) { + SDL_FreeSurface( surface ); + } + + // Clear the screen before drawing + glClear( GL_COLOR_BUFFER_BIT ); + + shaders(); + + // Bind the texture to which subsequent calls refer to + glBindTexture( GL_TEXTURE_2D, texture ); + + // Use clientside vertex pointers to render two items + GLfloat vertexData[] = { 0, 0, 10, 10, // texture2, position2 + 1, 0, 300, 10, + 1, 1, 300, 128, + 0, 1, 10, 128, + 0, 0.5, 410, 10, + 1, 0.5, 600, 10, + 1, 1, 630, 200, + 0.5, 1, 310, 250, + 0, 0, 100, 300, + 1, 0, 300, 300, + 1, 1, 300, 400, + 0, 1, 100, 400 }; + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 4*4, &vertexData[0]); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(2, GL_FLOAT, 4*4, &vertexData[2]); + + glDrawArrays(GL_QUADS, 0, 4); + + glTexCoordPointer(2, GL_FLOAT, 4*4*2, &vertexData[0]); // and now with a different stride + glVertexPointer(2, GL_FLOAT, 4*4*2, &vertexData[2]); + glDrawArrays(GL_QUADS, 4, 4); + + glTexCoordPointer(2, GL_FLOAT, 4*4, &vertexData[0]); // and back + glVertexPointer(2, GL_FLOAT, 4*4, &vertexData[2]); + glDrawArrays(GL_QUADS, 8, 4); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + SDL_GL_SwapBuffers(); + +#if !EMSCRIPTEN + // Wait for 3 seconds to give us a chance to see the image + SDL_Delay(3000); +#endif + + // Now we can delete the OpenGL texture and close down SDL + glDeleteTextures( 1, &texture ); + + SDL_Quit(); + + return 0; +} diff --git a/tests/gl_ps_strides.png b/tests/gl_ps_strides.png Binary files differnew file mode 100644 index 00000000..5b49af36 --- /dev/null +++ b/tests/gl_ps_strides.png diff --git a/tests/openal_playback.cpp b/tests/openal_playback.cpp new file mode 100644 index 00000000..13d619e6 --- /dev/null +++ b/tests/openal_playback.cpp @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <stdlib.h> +#include <AL/al.h> +#include <AL/alc.h> +#include <assert.h> +#include <emscripten.h> + +void playSource(void* arg) +{ + ALuint source = reinterpret_cast<ALuint>(arg); + ALint state; + alGetSourcei(source, AL_SOURCE_STATE, &state); + assert(state == AL_PLAYING); + alSourcePause(source); + alGetSourcei(source, AL_SOURCE_STATE, &state); + assert(state == AL_PAUSED); + alSourcePlay(source); + alGetSourcei(source, AL_SOURCE_STATE, &state); + assert(state == AL_PLAYING); + alSourceStop(source); + alGetSourcei(source, AL_SOURCE_STATE, &state); + assert(state == AL_STOPPED); + + int result = 1; + REPORT_RESULT(); +} + +int main() { + ALCdevice* device = alcOpenDevice(NULL); + ALCcontext* context = alcCreateContext(device, NULL); + alcMakeContextCurrent(context); + + ALfloat listenerPos[] = {0.0, 0.0, 0.0}; + ALfloat listenerVel[] = {0.0, 0.0, 0.0}; + ALfloat listenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0}; + + alListenerfv(AL_POSITION, listenerPos); + alListenerfv(AL_VELOCITY, listenerVel); + alListenerfv(AL_ORIENTATION, listenerOri); + + ALuint buffers[1]; + + alGenBuffers(1, buffers); + + FILE* source = fopen("audio.wav", "rb"); + fseek(source, 0, SEEK_END); + int size = ftell(source); + fseek(source, 0, SEEK_SET); + + unsigned char* buffer = (unsigned char*) malloc(size); + fread(buffer, size, 1, source); + + unsigned offset = 12; // ignore the RIFF header + offset += 8; // ignore the fmt header + offset += 2; // ignore the format type + + unsigned channels = buffer[offset + 1] << 8; + channels |= buffer[offset]; + offset += 2; + printf("Channels: %u\n", channels); + + unsigned frequency = buffer[offset + 3] << 24; + frequency |= buffer[offset + 2] << 16; + frequency |= buffer[offset + 1] << 8; + frequency |= buffer[offset]; + offset += 4; + printf("Frequency: %u\n", frequency); + + offset += 6; // ignore block size and bps + + unsigned bits = buffer[offset + 1] << 8; + bits |= buffer[offset]; + offset += 2; + printf("Bits: %u\n", bits); + + ALenum format = 0; + if(bits == 8) + { + if(channels == 1) + format = AL_FORMAT_MONO8; + else if(channels == 2) + format = AL_FORMAT_STEREO8; + } + else if(bits == 16) + { + if(channels == 1) + format = AL_FORMAT_MONO16; + else if(channels == 2) + format = AL_FORMAT_STEREO16; + } + + offset += 8; // ignore the data chunk + + printf("Start offset: %d\n", offset); + + alBufferData(buffers[0], format, &buffer[offset], size - offset, frequency); + + ALuint sources[1]; + alGenSources(1, sources); + + alSourcei(sources[0], AL_BUFFER, buffers[0]); + + ALint state; + alGetSourcei(sources[0], AL_SOURCE_STATE, &state); + assert(state == AL_INITIAL); + + alSourcePlay(sources[0]); + + alGetSourcei(sources[0], AL_SOURCE_STATE, &state); + assert(state == AL_PLAYING); + + emscripten_async_call(playSource, reinterpret_cast<void*>(sources[0]), 700); + + return 0; +} diff --git a/tests/runner.py b/tests/runner.py index 99c536e3..529dcc48 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -829,11 +829,14 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows int add_low = add; int add_high = add >> 32; printf("*%lld,%lld,%u,%u*\n", mul, add, add_low, add_high); + int64 x = sec + (usec << 25); + x >>= argc*3; + printf("*%llu*\n", x); return 0; } ''' - self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n') + self.do_run(src, '*1329409676000000,1329412005509675,3663280683,309527*\n*9770671914067409*\n') def test_i64_cmp(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2') @@ -1003,12 +1006,6 @@ m_divisor is 1091269979 ''' self.do_run(src, open(path_from_root('tests', 'i64_precise.txt')).read()) - # Verify that without precision, we do not include the precision code - Settings.PRECISE_I64_MATH = 0 - self.do_run(src, 'unsigned') - code = open(os.path.join(self.get_dir(), 'src.cpp.o.js')).read() - assert 'goog.math.Long' not in code, 'i64 precise math should not have been included if not asked for' - # Verify that even if we ask for precision, if it is not needed it is not included Settings.PRECISE_I64_MATH = 1 src = ''' @@ -1890,13 +1887,34 @@ Succeeded! printf("%s\\n", strdup_val); free(strdup_val); + { + char *one = "one 1 ONE !"; + char *two = "two 2 TWO ?"; + char three[1024]; + memset(three, '.', 1024); + three[50] = 0; + strncpy(three + argc, one + (argc/2), argc+1); + strncpy(three + argc*3, two + (argc/3), argc+2); + printf("waka %s\\n", three); + } + + { + char *one = "string number one top notch"; + char *two = "fa la sa ho fi FI FO FUM WHEN WHERE WHY HOW WHO"; + char three[1000]; + strcpy(three, &one[argc*2]); + strcat(three, &two[argc*3]); + printf("cat |%s|\\n", three); + } + return 0; } ''' for named in (0, 1): print named Settings.NAMED_GLOBALS = named - self.do_run(src, '4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\n', ['wowie', 'too', '74']) + self.do_run(src, '''4:10,177,543,def\n4\nwowie\ntoo\n76\n5\n(null)\n/* a comment */\n// another\ntest\nwaka ....e 1 O...wo 2 T................................ +cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too', '74']) if self.emcc_args == []: gen = open(self.in_dir('src.cpp.o.js')).read() assert ('var __str1;' in gen) == named @@ -4117,10 +4135,12 @@ The current type of b is: 9 #define CONSTRLEN 32 + char * (*func)(char *, const char *) = NULL; + void conoutfv(const char *fmt) { static char buf[CONSTRLEN]; - strcpy(buf, fmt); + func(buf, fmt); // call by function pointer to make sure we test strcpy here puts(buf); } @@ -4142,6 +4162,7 @@ The current type of b is: 9 }; int main() { + func = &strcpy; conoutfv("*staticccz*"); printf("*%.2f,%.2f,%.2f*\\n", S::getIdentity().x, S::getIdentity().y, S::getIdentity().z); return 0; @@ -5232,6 +5253,62 @@ at function.:blag ''' self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected)) + def test_vsnprintf(self): + if self.emcc_args is None: return self.skip('needs i64 math') + + src = r''' + #include <stdio.h> + #include <stdarg.h> + #include <stdint.h> + + void printy(const char *f, ...) + { + char buffer[256]; + va_list args; + va_start(args, f); + vsnprintf(buffer, 256, f, args); + puts(buffer); + va_end(args); + } + + int main(int argc, char **argv) { + int64_t x = argc - 1; + int64_t y = argc - 1 + 0x400000; + if (x % 3 == 2) y *= 2; + + printy("0x%llx_0x%llx", x, y); + printy("0x%llx_0x%llx", x, x); + printy("0x%llx_0x%llx", y, x); + printy("0x%llx_0x%llx", y, y); + + { + uint64_t A = 0x800000; + uint64_t B = 0x800000000000ULL; + printy("0x%llx_0x%llx", A, B); + } + { + uint64_t A = 0x800; + uint64_t B = 0x12340000000000ULL; + printy("0x%llx_0x%llx", A, B); + } + { + uint64_t A = 0x000009182746756; + uint64_t B = 0x192837465631ACBDULL; + printy("0x%llx_0x%llx", A, B); + } + + return 0; + } + ''' + self.do_run(src, '''0x0_0x400000 +0x0_0x0 +0x400000_0x0 +0x400000_0x400000 +0x800000_0x800000000000 +0x800_0x12340000000000 +0x9182746756_0x192837465631acbd +''') + def test_printf_more(self): src = r''' #include <stdio.h> @@ -6497,6 +6574,90 @@ PORT: 3979 expected = open(path_from_root('tests', 'ctype', 'output.txt'), 'r').read() self.do_run(src, expected) + def test_strcasecmp(self): + src = r''' + #include <stdio.h> + #include <strings.h> + int sign(int x) { + if (x < 0) return -1; + if (x > 0) return 1; + return 0; + } + int main() { + printf("*\n"); + + printf("%d\n", sign(strcasecmp("hello", "hello"))); + printf("%d\n", sign(strcasecmp("hello1", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "hello1"))); + printf("%d\n", sign(strcasecmp("hello1", "hello1"))); + printf("%d\n", sign(strcasecmp("iello", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "iello"))); + printf("%d\n", sign(strcasecmp("A", "hello"))); + printf("%d\n", sign(strcasecmp("Z", "hello"))); + printf("%d\n", sign(strcasecmp("a", "hello"))); + printf("%d\n", sign(strcasecmp("z", "hello"))); + printf("%d\n", sign(strcasecmp("hello", "a"))); + printf("%d\n", sign(strcasecmp("hello", "z"))); + + printf("%d\n", sign(strcasecmp("Hello", "hello"))); + printf("%d\n", sign(strcasecmp("Hello1", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "hello1"))); + printf("%d\n", sign(strcasecmp("Hello1", "hello1"))); + printf("%d\n", sign(strcasecmp("Iello", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "iello"))); + printf("%d\n", sign(strcasecmp("A", "hello"))); + printf("%d\n", sign(strcasecmp("Z", "hello"))); + printf("%d\n", sign(strcasecmp("a", "hello"))); + printf("%d\n", sign(strcasecmp("z", "hello"))); + printf("%d\n", sign(strcasecmp("Hello", "a"))); + printf("%d\n", sign(strcasecmp("Hello", "z"))); + + printf("%d\n", sign(strcasecmp("hello", "Hello"))); + printf("%d\n", sign(strcasecmp("hello1", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "Hello1"))); + printf("%d\n", sign(strcasecmp("hello1", "Hello1"))); + printf("%d\n", sign(strcasecmp("iello", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "Iello"))); + printf("%d\n", sign(strcasecmp("A", "Hello"))); + printf("%d\n", sign(strcasecmp("Z", "Hello"))); + printf("%d\n", sign(strcasecmp("a", "Hello"))); + printf("%d\n", sign(strcasecmp("z", "Hello"))); + printf("%d\n", sign(strcasecmp("hello", "a"))); + printf("%d\n", sign(strcasecmp("hello", "z"))); + + printf("%d\n", sign(strcasecmp("Hello", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello1", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "Hello1"))); + printf("%d\n", sign(strcasecmp("Hello1", "Hello1"))); + printf("%d\n", sign(strcasecmp("Iello", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "Iello"))); + printf("%d\n", sign(strcasecmp("A", "Hello"))); + printf("%d\n", sign(strcasecmp("Z", "Hello"))); + printf("%d\n", sign(strcasecmp("a", "Hello"))); + printf("%d\n", sign(strcasecmp("z", "Hello"))); + printf("%d\n", sign(strcasecmp("Hello", "a"))); + printf("%d\n", sign(strcasecmp("Hello", "z"))); + + printf("%d\n", sign(strncasecmp("hello", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello1", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "hello1", 3))); + printf("%d\n", sign(strncasecmp("hello1", "hello1", 3))); + printf("%d\n", sign(strncasecmp("iello", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "iello", 3))); + printf("%d\n", sign(strncasecmp("A", "hello", 3))); + printf("%d\n", sign(strncasecmp("Z", "hello", 3))); + printf("%d\n", sign(strncasecmp("a", "hello", 3))); + printf("%d\n", sign(strncasecmp("z", "hello", 3))); + printf("%d\n", sign(strncasecmp("hello", "a", 3))); + printf("%d\n", sign(strncasecmp("hello", "z", 3))); + + printf("*\n"); + + return 0; + } + ''' + self.do_run(src, '''*\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n1\n-1\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n0\n0\n0\n0\n1\n-1\n-1\n1\n-1\n1\n1\n-1\n*\n''') + def test_atomic(self): src = ''' #include <stdio.h> @@ -7202,6 +7363,8 @@ def process(filename): if self.emcc_args is None: return self.skip('requires emcc') if Building.LLVM_OPTS and self.emcc_args is None: Settings.SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore + Settings.DEAD_FUNCTIONS = ['__ZSt9terminatev'] + # Note: this is also a good test of per-file and per-line changes (since we have multiple files, and correct specific lines) if Settings.SAFE_HEAP: # Ignore bitfield warnings @@ -7782,20 +7945,32 @@ def process(filename): self.emcc_args = map(lambda x: 'ASM_JS=1' if x == 'ASM_JS=0' else x, self.emcc_args) shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgo.js')) - pgo_output = run_js(self.in_dir('pgo.js')) + pgo_output = run_js(self.in_dir('pgo.js')).split('\n')[1] + open('pgo_data', 'w').write(pgo_output) + + # with response file - open('pgo_data', 'w').write(pgo_output.split('\n')[1]) self.emcc_args += ['@pgo_data'] self.do_run(src, output) + self.emcc_args.pop() shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed.js')) before = len(open('normal.js').read()) after = len(open('pgoed.js').read()) assert after < 0.66 * before, [before, after] # expect a big size reduction + # with response in settings element itself + + open('dead_funcs', 'w').write(pgo_output[pgo_output.find('['):-1]) + self.emcc_args += ['-s', 'DEAD_FUNCTIONS=@' + self.in_dir('dead_funcs')] + self.do_run(src, output) + shutil.move(self.in_dir('src.cpp.o.js'), self.in_dir('pgoed2.js')) + assert open('pgoed.js').read() == open('pgoed2.js').read() + def test_scriptaclass(self): if self.emcc_args is None: return self.skip('requires emcc') - if Settings.ASM_JS: return self.skip('asm does not bindings generator yet') + + Settings.EXPORT_BINDINGS = 1 header_filename = os.path.join(self.get_dir(), 'header.h') header = ''' @@ -7970,6 +8145,7 @@ def process(filename): Module.Child2.prototype.runVirtualFunc(c2); c2.virtualFunc2(); +''' + ('' if Settings.ASM_JS else ''' // extend the class from JS var c3 = new Module.Child2; Module.customizeVTable(c3, [{ @@ -7990,6 +8166,7 @@ def process(filename): c2.virtualFunc(); // original should remain the same Module.Child2.prototype.runVirtualFunc(c2); c2.virtualFunc2(); +''') + ''' Module.print('*ok*'); \'\'\' @@ -8028,7 +8205,7 @@ Child2:9 *static* *virtualf* *virtualf* -*virtualf2* +*virtualf2*''' + ('' if Settings.ASM_JS else ''' Parent:9 Child2:9 *js virtualf replacement* @@ -8036,13 +8213,14 @@ Child2:9 *js virtualf2 replacement* *virtualf* *virtualf* -*virtualf2* +*virtualf2*''') + ''' *ok* ''', post_build=[post2, post3]) def test_scriptaclass_2(self): if self.emcc_args is None: return self.skip('requires emcc') - if Settings.ASM_JS: return self.skip('asm does not bindings generator yet') + + Settings.EXPORT_BINDINGS = 1 header_filename = os.path.join(self.get_dir(), 'header.h') header = ''' @@ -9196,7 +9374,7 @@ f.close() filename = self.in_dir('src.cpp') open(filename, 'w').write(src) out, err = Popen([PYTHON, EMCC, filename, '-s', 'ASM_JS=1', '-O2'], stderr=PIPE).communicate() - assert 'Warning: Unresolved symbol' in err, 'always warn on undefs in asm, since it breaks validation' + assert 'Unresolved symbol' in err, 'always warn on undefs in asm, since it breaks validation: ' + err def test_redundant_link(self): lib = "int mult() { return 1; }" @@ -9841,11 +10019,11 @@ f.close() try: os.environ['EMCC_DEBUG'] = '1' for asm, linkable, chunks, js_chunks in [ - (0, 0, 3, 2), (0, 1, 3, 4), - (1, 0, 3, 2), (1, 1, 3, 4) + (0, 0, 3, 2), (0, 1, 4, 4), + (1, 0, 3, 2), (1, 1, 4, 5) ]: print asm, linkable, chunks, js_chunks - output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm], stdout=PIPE, stderr=PIPE).communicate() + output, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_libcxx.cpp'), '-O1', '-s', 'LINKABLE=%d' % linkable, '-s', 'ASM_JS=%d' % asm, '-s', 'UNRESOLVED_AS_DEAD=1'], stdout=PIPE, stderr=PIPE).communicate() assert 'phase 2 working on %d chunks' %chunks in err, err assert 'splitting up js optimization into %d chunks' % js_chunks in err, err finally: @@ -10892,6 +11070,13 @@ elif 'browser' in str(sys.argv): Popen([PYTHON, EMCC, path_from_root('tests', 'sdl_fog_linear.c'), '-o', 'something.html', '--pre-js', 'reftest.js', '--preload-file', 'screenshot.png', '-s', 'GL_TESTING=1']).communicate() self.run_browser('something.html', 'You should see an image with fog.', '/report_result?0') + def test_openal_playback(self): + shutil.copyfile(path_from_root('tests', 'sounds', 'audio.wav'), os.path.join(self.get_dir(), 'audio.wav')) + open(os.path.join(self.get_dir(), 'openal_playback.cpp'), 'w').write(self.with_report_result(open(path_from_root('tests', 'openal_playback.cpp')).read())) + + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'openal_playback.cpp'), '--preload-file', 'audio.wav', '-o', 'page.html']).communicate() + self.run_browser('page.html', '', '/report_result?1') + def test_worker(self): # Test running in a web worker output = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world_worker.cpp'), '-o', 'worker.js'], stdout=PIPE, stderr=PIPE).communicate() @@ -11178,6 +11363,10 @@ elif 'browser' in str(sys.argv): shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) self.btest('gl_ps_workaround2.c', reference='gl_ps.png', args=['--preload-file', 'screenshot.png']) + def test_gl_ps_strides(self): + shutil.copyfile(path_from_root('tests', 'screenshot.png'), os.path.join(self.get_dir(), 'screenshot.png')) + self.btest('gl_ps_strides.c', reference='gl_ps_strides.png', args=['--preload-file', 'screenshot.png']) + def test_matrix_identity(self): self.btest('gl_matrix_identity.c', expected=['-1882984448', '460451840']) @@ -11639,7 +11828,8 @@ elif 'benchmark' in str(sys.argv): start = time.time() js_output = run_js(final_filename, engine=JS_ENGINE, args=args, stderr=PIPE, full_output=True) if i == 0 and 'Successfully compiled asm.js code' in js_output: - print "[%s was asm.js'ified]" % name + if 'asm.js link error' not in js_output: + print "[%s was asm.js'ified]" % name curr = time.time()-start times.append(curr) total_times[tests_done] += curr @@ -11907,7 +12097,8 @@ ok. native=True) emcc_args = js_lib + ['-I' + path_from_root('tests', 'bullet', 'src'), - '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks')] + '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks'), + '-s', 'DEAD_FUNCTIONS=["__ZSt9terminatev"]'] native_args = native_lib + ['-I' + path_from_root('tests', 'bullet', 'src'), '-I' + path_from_root('tests', 'bullet', 'Demos', 'Benchmarks')] @@ -12306,9 +12497,9 @@ fi assert ('bootstrapping relooper succeeded' in output) == (i == 2), 'only bootstrap on first O2: ' + output assert os.path.exists(RELOOPER) == (i >= 2), 'have relooper on O2: ' + output src = open('a.out.js').read() - main = src.split('function _main() {')[1].split('\n}\n')[0] - assert ('while (1) {' in main) == (i >= 2), 'reloop code on O2: ' + src - assert ('switch' not in main) == (i >= 2), 'reloop code on O2: ' + src + main = src.split('function _main()')[1].split('\n}\n')[0] + assert ('while (1) {' in main or 'while(1){' in main) == (i >= 2), 'reloop code on O2: ' + main + assert ('switch' not in main) == (i >= 2), 'reloop code on O2: ' + main def test_jcache(self): PRE_LOAD_MSG = 'loading pre from jcache' diff --git a/tests/sdl_audio_mix.c b/tests/sdl_audio_mix.c index e3431e0c..f72f9c43 100644 --- a/tests/sdl_audio_mix.c +++ b/tests/sdl_audio_mix.c @@ -49,6 +49,8 @@ void one_iter() { case 120: Mix_HaltChannel(soundChannel); Mix_HaltMusic(); + int result = 1; + REPORT_RESULT(); break; }; } diff --git a/tests/sounds/audio.wav b/tests/sounds/audio.wav Binary files differnew file mode 100644 index 00000000..dd1b8057 --- /dev/null +++ b/tests/sounds/audio.wav diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index d2c165a2..d610ab54 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -62,6 +62,10 @@ Notes: string on the *stack*. The C string will live for the current function call. If you need it for longer, you need to create a copy in your C++ code. + + * You should compile with -s EXPORT_BINDINGS=1 in order for the + autogenerated bindings functions to be exported. This is necessary + when compiling in asm.js mode. ''' import os, sys, glob, re @@ -464,6 +468,7 @@ Module['getClass'] = getClass; function customizeVTable(object, replacementPairs) { // Does not handle multiple inheritance + // Does not work with asm.js // Find out vtable size var vTable = getValue(object.ptr, 'void*'); diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 87fd0660..1f1c1354 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -154,7 +154,7 @@ def run_on_js(filename, passes, js_engine, jcache): class Finals: buf = [] def process(line): - if len(line) > 0 and (line.startswith('Module[') or line.endswith('["X"]=1;')): + if len(line) > 0 and (line.startswith(('Module[', 'if (globalScope)')) or line.endswith('["X"]=1;')): Finals.buf.append(line) return False return True diff --git a/tools/settings_template_readonly.py b/tools/settings_template_readonly.py index f689e205..7ab89b48 100644 --- a/tools/settings_template_readonly.py +++ b/tools/settings_template_readonly.py @@ -11,8 +11,7 @@ PYTHON = os.path.expanduser(os.getenv('PYTHON') or '{{{ PYTHON }}}') # executabl # See below for notes on which JS engine(s) you need NODE_JS = os.path.expanduser(os.getenv('NODE') or '{{{ NODE }}}') # executable -SPIDERMONKEY_ENGINE = [ - os.path.expanduser(os.getenv('SPIDERMONKEY') or 'js'), '-m', '-n'] # executable +SPIDERMONKEY_ENGINE = [os.path.expanduser(os.getenv('SPIDERMONKEY') or 'js')] # executable V8_ENGINE = os.path.expanduser(os.getenv('V8') or 'd8') # executable JAVA = 'java' # executable diff --git a/tools/shared.py b/tools/shared.py index 34ed9b3d..3d0f90b9 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -181,7 +181,7 @@ def check_node_version(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.3.0' +EMSCRIPTEN_VERSION = '1.3.1' def check_sanity(force=False): try: @@ -1141,6 +1141,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e print >> sys.stderr, 'bootstrapping relooper...' os.chdir(path_from_root('src')) + emcc_debug = os.environ.get('EMCC_DEBUG') + if emcc_debug: del os.environ['EMCC_DEBUG'] + def make(opt_level): raw = relooper + '.raw.js' Building.emcc(os.path.join('relooper', 'Relooper.cpp'), ['-I' + os.path.join('relooper'), '--post-js', @@ -1169,6 +1172,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' % { 'winfix': '' if not WINDOWS e ok = True finally: os.chdir(curr) + if emcc_debug: os.environ['EMCC_DEBUG'] = emcc_debug if not ok: print >> sys.stderr, 'bootstrapping relooper failed. You may need to manually create relooper.js by compiling it, see src/relooper/emscripten' 1/0 |