diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rwxr-xr-x | emscripten.py | 4 | ||||
-rw-r--r-- | src/jsifier.js | 11 | ||||
-rw-r--r-- | src/library.js | 402 | ||||
-rw-r--r-- | src/library_browser.js | 54 | ||||
-rw-r--r-- | src/library_gl.js | 109 | ||||
-rw-r--r-- | src/library_openal.js | 154 | ||||
-rw-r--r-- | src/library_sdl.js | 19 | ||||
-rw-r--r-- | src/parseTools.js | 4 | ||||
-rw-r--r-- | src/preamble.js | 48 | ||||
-rw-r--r-- | src/settings.js | 16 | ||||
-rw-r--r-- | src/shell.html | 8 | ||||
-rw-r--r-- | system/include/libc/ctype.h | 44 | ||||
-rw-r--r-- | tests/cases/alignedunaligned.ll | 6 | ||||
-rw-r--r-- | tests/cases/phicubed.ll | 29 | ||||
-rw-r--r-- | tests/cases/storestruct.ll | 5 | ||||
-rw-r--r-- | tests/cases/unannotated__noasm.ll (renamed from tests/cases/unannotated.ll) | 0 | ||||
-rw-r--r-- | tests/cases/unannotated__noasm.txt (renamed from tests/cases/unannotated.txt) | 0 | ||||
-rw-r--r-- | tests/gl_ps_strides.c | 241 | ||||
-rw-r--r-- | tests/gl_ps_strides.png | bin | 0 -> 98713 bytes | |||
-rwxr-xr-x | tests/runner.py | 181 | ||||
-rwxr-xr-x | tools/bindings_generator.py | 5 | ||||
-rw-r--r-- | tools/js-optimizer.js | 11 | ||||
-rw-r--r-- | tools/shared.py | 2 |
24 files changed, 977 insertions, 377 deletions
@@ -54,4 +54,5 @@ a license to everyone to use it as detailed in LICENSE.) * Lorant Pinter <lorant.pinter@prezi.com> * Tobias Doerffel <tobias.doerffel@gmail.com> * Martin von Gagern <martin@von-gagern.net> +* Ting-Yuan Huang <thuang@mozilla.com> diff --git a/emscripten.py b/emscripten.py index 0698c783..c9d8505d 100755 --- a/emscripten.py +++ b/emscripten.py @@ -269,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 diff --git a/src/jsifier.js b/src/jsifier.js index 4263618a..7db2ee70 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -512,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; @@ -722,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 = {'; diff --git a/src/library.js b/src/library.js index 45187d8d..aebad63b 100644 --- a/src/library.js +++ b/src/library.js @@ -382,7 +382,7 @@ LibraryManager.library = { // do preloading for the Image/Audio part, as if the typed array were the // result of an XHR that you did manually. createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) { - Browser.ensureObjects(); + Browser.init(); var fullname = FS.joinPath([parent, name], true); function processData(byteArray) { function finish(byteArray) { @@ -2638,11 +2638,11 @@ 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. - _formatString__deps: ['strlen'], + _formatString__deps: ['strlen', '_reallyNegative'], _formatString: function(format, varargs) { var textIndex = format; var argIndex = 0; @@ -2782,226 +2782,251 @@ 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 == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}; - 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 == {{{ charCode('u') }}}); - } + // 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 == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}) { + // 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 == {{{ charCode('u') }}}) { + 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 == {{{ charCode('o') }}}) { - argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8); - } else if (next == {{{ charCode('x') }}} || next == {{{ charCode('X') }}}) { - 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 == {{{ 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); } - } - 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 == {{{ 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; + 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); + if (currArg === 0 && __reallyNegative(currArg)) { + argText = '-' + argText; + } + } + + 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 == {{{ charCode('g') }}}) ? '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] : ''); - 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); + // Capitalize 'E' if needed. + if (next == {{{ charCode('E') }}}) argText = argText.toUpperCase(); + + // Add sign. + if (flagAlwaysSigned && currArg >= 0) { + argText = '+' + argText; } - } 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); + // 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 == {{{ charCode('E') }}}) 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 < {{{ charCode('a') }}}) argText = argText.toUpperCase(); - - // Insert the result into the buffer. - argText.split('').forEach(function(chr) { - ret.push(chr.charCodeAt(0)); - }); - } else if (next == {{{ charCode('s') }}}) { - // String. - var arg = getNextArg('i8*') || nullString; - var argLength = _strlen(arg); - if (precisionSet) argLength = Math.min(argLength, precision); - if (!flagLeftAlign) { - while (argLength < width--) { + 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({{{ charCode(' ') }}}); - } + 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 == {{{ charCode('c') }}}) { - // Character. - if (flagLeftAlign) ret.push(getNextArg('i8')); - while (--width > 0) { - ret.push({{{ charCode(' ') }}}); + case '%': { + // Literal percent sign. + ret.push(curr); + break; } - if (!flagLeftAlign) ret.push(getNextArg('i8')); - } else if (next == {{{ charCode('n') }}}) { - // Write the length written so far to the next parameter. - var ptr = getNextArg('i32*'); - {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}} - } else if (next == {{{ charCode('%') }}}) { - // 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; @@ -3147,7 +3172,7 @@ LibraryManager.library = { for (var i = 0; i < n - 1 && byte_ != {{{ charCode('\n') }}}; i++) { byte_ = _fgetc(stream); if (byte_ == -1) { - if (streamObj.error) return 0; + if (streamObj.error || (streamObj.eof && i == 0)) return 0; else if (streamObj.eof) break; } {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}} @@ -4927,7 +4952,7 @@ LibraryManager.library = { var ret = 0; while (x) { if (x&1) ret++; - x >>= 1; + x >>>= 1; } return ret; }, @@ -5455,9 +5480,14 @@ LibraryManager.library = { return isNaN(x); }, __isnan: 'isnan', + + _reallyNegative: function(x) { + return x < 0 || (x === 0 && (1/x) === -Infinity); + }, + + copysign__deps: ['_reallyNegative'], copysign: function(a, b) { - if (a < 0 === b < 0) return a; - return -a; + return __reallyNegative(a) === __reallyNegative(b) ? a : -a; }, copysignf: 'copysign', __signbit__deps: ['copysign'], diff --git a/src/library_browser.js b/src/library_browser.js index bdd94bac..e61f84b5 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -45,9 +45,9 @@ mergeInto(LibraryManager.library, { moduleContextCreatedCallbacks: [], workers: [], - ensureObjects: function() { - if (Browser.ensured) return; - Browser.ensured = true; + init: function() { + if (Browser.initted) return; + Browser.initted = true; try { new Blob(); Browser.hasBlobConstructor = true; @@ -193,6 +193,36 @@ mergeInto(LibraryManager.library, { } }; Module['preloadPlugins'].push(audioPlugin); + + // Canvas event setup + + var canvas = Module['canvas']; + canvas.requestPointerLock = canvas['requestPointerLock'] || + canvas['mozRequestPointerLock'] || + canvas['webkitRequestPointerLock']; + canvas.exitPointerLock = document['exitPointerLock'] || + document['mozExitPointerLock'] || + document['webkitExitPointerLock']; + canvas.exitPointerLock = canvas.exitPointerLock.bind(document); + + function pointerLockChange() { + Browser.pointerLock = document['pointerLockElement'] === canvas || + document['mozPointerLockElement'] === canvas || + document['webkitPointerLockElement'] === canvas; + } + + document.addEventListener('pointerlockchange', pointerLockChange, false); + document.addEventListener('mozpointerlockchange', pointerLockChange, false); + document.addEventListener('webkitpointerlockchange', pointerLockChange, false); + + if (Module['elementPointerLock']) { + canvas.addEventListener("click", function(ev) { + if (!Browser.pointerLock && canvas.requestPointerLock) { + canvas.requestPointerLock(); + ev.preventDefault(); + } + }, false); + } }, createContext: function(canvas, useWebGL, setInModule) { @@ -271,6 +301,7 @@ mergeInto(LibraryManager.library, { Module.ctx = ctx; Module.useWebGL = useWebGL; Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() }); + Browser.init(); } return ctx; }, @@ -292,13 +323,6 @@ mergeInto(LibraryManager.library, { if ((document['webkitFullScreenElement'] || document['webkitFullscreenElement'] || document['mozFullScreenElement'] || document['mozFullscreenElement'] || document['fullScreenElement'] || document['fullscreenElement']) === canvas) { - canvas.requestPointerLock = canvas['requestPointerLock'] || - canvas['mozRequestPointerLock'] || - canvas['webkitRequestPointerLock']; - canvas.exitPointerLock = document['exitPointerLock'] || - document['mozExitPointerLock'] || - document['webkitExitPointerLock']; - canvas.exitPointerLock = canvas.exitPointerLock.bind(document); canvas.cancelFullScreen = document['cancelFullScreen'] || document['mozCancelFullScreen'] || document['webkitCancelFullScreen']; @@ -312,21 +336,11 @@ mergeInto(LibraryManager.library, { if (Module['onFullScreen']) Module['onFullScreen'](Browser.isFullScreen); } - function pointerLockChange() { - Browser.pointerLock = document['pointerLockElement'] === canvas || - document['mozPointerLockElement'] === canvas || - document['webkitPointerLockElement'] === canvas; - } - if (!this.fullScreenHandlersInstalled) { this.fullScreenHandlersInstalled = true; document.addEventListener('fullscreenchange', fullScreenChange, false); document.addEventListener('mozfullscreenchange', fullScreenChange, false); document.addEventListener('webkitfullscreenchange', fullScreenChange, false); - - document.addEventListener('pointerlockchange', pointerLockChange, false); - document.addEventListener('mozpointerlockchange', pointerLockChange, false); - document.addEventListener('webkitpointerlockchange', pointerLockChange, false); } canvas.requestFullScreen = canvas['requestFullScreen'] || 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 index 5511ccb7..719d8cf8 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -41,7 +41,9 @@ var LibraryOpenAL = { } if (attrList) { +#if OPENAL_DEBUG console.log("The attrList argument of alcCreateContext is not supported yet"); +#endif return 0; } @@ -55,6 +57,7 @@ var LibraryOpenAL = { } if (ctx) { + ctx.listener.panningModel = "equalpower"; AL.contexts.push({ctx: ctx, err: 0, src: [], buf: []}); return AL.contexts.length; } else { @@ -73,18 +76,22 @@ var LibraryOpenAL = { 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; + var sourceIdx = {{{ makeGetValue('sources', 'i*4', '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) { @@ -107,17 +114,21 @@ var LibraryOpenAL = { playTime: -1, pausedTime: 0 }); - {{{ makeSetValue('sources', 'i', 'AL.currentContext.src.length', 'i32') }}}; + {{{ makeSetValue('sources', 'i*4', '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) { @@ -132,18 +143,24 @@ var LibraryOpenAL = { } break; default: +#if OPENAL_DEBUG console.log("alSourcei with param " + param + " not implemented yet"); +#endif break; } }, alSourcef: function(source, param, value) { if (!AL.currentContext) { - consoue.error("alSourcef called without a valid context"); +#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) { @@ -151,61 +168,79 @@ var LibraryOpenAL = { 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) { - consoue.error("alSourcefv called without a valid context"); +#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') }}} + {{{ makeGetValue('value', '4', 'float') }}}, + {{{ makeGetValue('value', '8', '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') }}} + {{{ makeGetValue('value', '4', 'float') }}}, + {{{ makeGetValue('value', '8', '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') }}}; + var buffer = {{{ makeGetValue('buffers', 'i*4', '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; @@ -215,22 +250,28 @@ var LibraryOpenAL = { 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') }}}; + {{{ makeSetValue('buffers', 'i*4', 'j+1', 'i32') }}}; AL.currentContext.src[source - 1].buffer = null; break; } @@ -241,11 +282,13 @@ var LibraryOpenAL = { 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 bufferIdx = {{{ makeGetValue('buffers', 'i*4', '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) { @@ -259,22 +302,28 @@ var LibraryOpenAL = { 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') }}}; + {{{ makeSetValue('buffers', 'i*4', '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; @@ -296,7 +345,9 @@ var LibraryOpenAL = { 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); @@ -323,22 +374,30 @@ var LibraryOpenAL = { 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; + if ("src" in AL.currentContext.src[source - 1] && + AL.currentContext.src[source - 1]["src"].buffer == + AL.currentContext.src[source - 1].buffer) { + 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; + } else { + // 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); + } } var src = AL.currentContext.ctx.createBufferSource(); src.loop = AL.currentContext.src[source - 1].loop; @@ -353,11 +412,15 @@ var LibraryOpenAL = { 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]) { @@ -368,11 +431,15 @@ var LibraryOpenAL = { 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] && @@ -387,11 +454,15 @@ var LibraryOpenAL = { 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) { @@ -440,12 +511,50 @@ var LibraryOpenAL = { 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) { - console.log("alListenerfv is not supported yet"); + if (!AL.currentContext) { +#if OPENAL_DEBUG + console.error("alListenerfv called without a valid context"); +#endif + return; + } + switch (param) { + case 0x1004 /* AL_POSITION */: + AL.currentContext.ctx.listener.setPosition( + {{{ makeGetValue('values', '0', 'float') }}}, + {{{ makeGetValue('values', '4', 'float') }}}, + {{{ makeGetValue('values', '8', 'float') }}} + ); + break; + case 0x1006 /* AL_VELOCITY */: + AL.currentContext.ctx.listener.setVelocity( + {{{ makeGetValue('values', '0', 'float') }}}, + {{{ makeGetValue('values', '4', 'float') }}}, + {{{ makeGetValue('values', '8', 'float') }}} + ); + break; + case 0x100F /* AL_ORIENTATION */: + AL.currentContext.ctx.listener.setOrientation( + {{{ makeGetValue('values', '0', 'float') }}}, + {{{ makeGetValue('values', '4', 'float') }}}, + {{{ makeGetValue('values', '8', 'float') }}}, + {{{ makeGetValue('values', '12', 'float') }}}, + {{{ makeGetValue('values', '16', 'float') }}}, + {{{ makeGetValue('values', '20', 'float') }}} + ); + break; + default: +#if OPENAL_DEBUG + console.log("alListenerfv with param " + param + " not implemented yet"); +#endif + break; + } }, alIsExtensionPresent: function(extName) { @@ -464,6 +573,9 @@ var LibraryOpenAL = { return 0; }, + alcGetError: function(device) { + return 0; + }, }; autoAddDeps(LibraryOpenAL, '$AL'); diff --git a/src/library_sdl.js b/src/library_sdl.js index 9fc979d2..42207f23 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -524,8 +524,18 @@ 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 rect = Module["canvas"].getBoundingClientRect(); + var x = event.pageX - (window.scrollX + rect.left); + var y = event.pageY - (window.scrollY + rect.top); + + // the canvas might be CSS-scaled compared to its backbuffer; + // SDL-using content will want mouse coordinates in terms + // of backbuffer units. + var cw = Module["canvas"].width; + var ch = Module["canvas"].height; + x = x * (cw / rect.width); + y = y * (ch / rect.height); + var movementX = x - SDL.mouseX; var movementY = y - SDL.mouseY; } @@ -912,10 +922,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 rect = Module["canvas"].getBoundingClientRect(); SDL.events.push({ type: 'mousemove', - pageX: x + Module['canvas'].offsetLeft, - pageY: y + Module['canvas'].offsetTop + pageX: x + (window.scrollX + rect.left), + pageY: y + (window.scrollY + rect.top) }); }, diff --git a/src/parseTools.js b/src/parseTools.js index 2664baed..9fddacbb 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -818,7 +818,9 @@ function parseNumerical(value, type) { return '0'; } if (isNumber(value)) { - return parseFloat(value).toString(); // will change e.g. 5.000000e+01 to 50 + var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50 + if (type in Runtime.FLOAT_TYPES && value[0] == '-' && ret === 0) return '-0'; // fix negative 0, toString makes it 0 + return ret.toString(); } else { return value; } diff --git a/src/preamble.js b/src/preamble.js index 6f3a969c..2cff440c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -503,30 +503,44 @@ function allocate(slab, types, allocator, ptr) { Module['allocate'] = allocate; function Pointer_stringify(ptr, /* optional */ length) { -#if UTF_STRING_SUPPORT - 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; -#else -#if USE_TYPED_ARRAYS == 2 - return String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + (length || _strlen(ptr)))); -#else - throw 'unsupported combination'; -#endif -#endif } Module['Pointer_stringify'] = Pointer_stringify; @@ -556,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/settings.js b/src/settings.js index 36f53c3c..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) @@ -171,8 +173,6 @@ var GL_UNSAFE_OPTS = 1; // Enables some potentially-unsafe optimizations in GL e var FULL_ES2 = 0; // Forces support for all GLES2 features, not just the WebGL-friendly subset. var FORCE_GL_EMULATION = 0; // Forces inclusion of full GL emulation code. -var UTF_STRING_SUPPORT = 1; // Perform utf-8 conversion between C and JS strings (adds overhead in such conversions) - var DISABLE_EXCEPTION_CATCHING = 0; // Disables generating code to actually catch exceptions. If the code you // are compiling does not actually rely on catching exceptions (but the // compiler generates code for it, maybe because of stdlibc++ stuff), @@ -226,11 +226,13 @@ 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 // JS library functions (C functions implemented in JS) // that we include by default. If you want to make sure @@ -340,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/shell.html b/src/shell.html index 8743d403..f7eb9e1f 100644 --- a/src/shell.html +++ b/src/shell.html @@ -6,9 +6,11 @@ <title>Emscripten-Generated Code</title> <style> .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } - canvas.emscripten { border: 1px solid black; } textarea.emscripten { font-family: monospace; width: 80%; } div.emscripten { text-align: center; } + div.emscripten_border { border: 1px solid black; } + /* the canvas *must not* have any border or padding, or mouse coords will be wrong */ + canvas.emscripten { border: 0px none; } </style> </head> <body> @@ -17,7 +19,9 @@ <div class="emscripten"> <progress value="0" max="100" id="progress" hidden=1></progress> </div> - <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas> + <div class="emscripten_border"> + <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas> + </div> <hr/> <div class="emscripten"> <input type="checkbox" id="resize">Resize canvas diff --git a/system/include/libc/ctype.h b/system/include/libc/ctype.h index 383a8db1..666c4d7c 100644 --- a/system/include/libc/ctype.h +++ b/system/include/libc/ctype.h @@ -117,20 +117,6 @@ extern __IMPORT _CONST char _ctype_[]; _END_STD_C - - - - - - - - - - - - - - /* * Copyright (c) 2000, 2005, 2008 Apple Inc. All rights reserved. * @@ -196,25 +182,15 @@ _END_STD_C * @(#)ctype.h 8.4 (Berkeley) 1/21/94 */ -#define _CTYPE_A 0x00000100L /* Alpha */ -#define _CTYPE_C 0x00000200L /* Control */ -#define _CTYPE_D 0x00000400L /* Digit */ -#define _CTYPE_G 0x00000800L /* Graph */ -#define _CTYPE_L 0x00001000L /* Lower */ -#define _CTYPE_P 0x00002000L /* Punct */ -#define _CTYPE_S 0x00004000L /* Space */ -#define _CTYPE_U 0x00008000L /* Upper */ -#define _CTYPE_X 0x00010000L /* X digit */ -#define _CTYPE_B 0x00020000L /* Blank */ -#define _CTYPE_R 0x00040000L /* Print */ -#define _CTYPE_I 0x00080000L /* Ideogram */ -#define _CTYPE_T 0x00100000L /* Special */ -#define _CTYPE_Q 0x00200000L /* Phonogram */ -#define _CTYPE_SW0 0x20000000L /* 0 width character */ -#define _CTYPE_SW1 0x40000000L /* 1 width character */ -#define _CTYPE_SW2 0x80000000L /* 2 width character */ -#define _CTYPE_SW3 0xc0000000L /* 3 width character */ -#define _CTYPE_SWM 0xe0000000L /* Mask for screen width data */ -#define _CTYPE_SWS 30 /* Bits to shift to get width */ +#define _CTYPE_A 0x00000400 /* Alpha */ +#define _CTYPE_C 0x00000002 /* Control */ +#define _CTYPE_D 0x00000800 /* Digit */ +#define _CTYPE_L 0x00000200 /* Lower */ +#define _CTYPE_P 0x00000004 /* Punct */ +#define _CTYPE_S 0x00002000 /* Space */ +#define _CTYPE_U 0x00000100 /* Upper */ +#define _CTYPE_X 0x00001000 /* X digit */ +#define _CTYPE_B 0x00000001 /* Blank */ +#define _CTYPE_R 0x00004000 /* Print */ #endif /* _CTYPE_H_ */ 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/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/runner.py b/tests/runner.py index 7f46dbfb..168567d2 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -1234,6 +1234,59 @@ m_divisor is 1091269979 ''' self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,') + def test_negative_zero(self): + src = r''' + #include <stdio.h> + #include <math.h> + + int main() { + #define TEST(x, y) \ + printf("%.2f, %.2f ==> %.2f\n", x, y, copysign(x, y)); + TEST( 5.0f, 5.0f); + TEST( 5.0f, -5.0f); + TEST(-5.0f, 5.0f); + TEST(-5.0f, -5.0f); + TEST( 5.0f, 4.0f); + TEST( 5.0f, -4.0f); + TEST(-5.0f, 4.0f); + TEST(-5.0f, -4.0f); + TEST( 0.0f, 5.0f); + TEST( 0.0f, -5.0f); + TEST(-0.0f, 5.0f); + TEST(-0.0f, -5.0f); + TEST( 5.0f, 0.0f); + TEST( 5.0f, -0.0f); + TEST(-5.0f, 0.0f); + TEST(-5.0f, -0.0f); + TEST( 0.0f, 0.0f); + TEST( 0.0f, -0.0f); + TEST(-0.0f, 0.0f); + TEST(-0.0f, -0.0f); + return 0; + } + ''' + self.do_run(src, '''5.00, 5.00 ==> 5.00 +5.00, -5.00 ==> -5.00 +-5.00, 5.00 ==> 5.00 +-5.00, -5.00 ==> -5.00 +5.00, 4.00 ==> 5.00 +5.00, -4.00 ==> -5.00 +-5.00, 4.00 ==> 5.00 +-5.00, -4.00 ==> -5.00 +0.00, 5.00 ==> 0.00 +0.00, -5.00 ==> -0.00 +-0.00, 5.00 ==> 0.00 +-0.00, -5.00 ==> -0.00 +5.00, 0.00 ==> 5.00 +5.00, -0.00 ==> -5.00 +-5.00, 0.00 ==> 5.00 +-5.00, -0.00 ==> -5.00 +0.00, 0.00 ==> 0.00 +0.00, -0.00 ==> -0.00 +-0.00, 0.00 ==> 0.00 +-0.00, -0.00 ==> -0.00 +''') + def test_llvm_intrinsics(self): if self.emcc_args == None: return self.skip('needs ta2') @@ -1269,6 +1322,7 @@ m_divisor is 1091269979 printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10)); printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10)); printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101)); + printf("%d\n", (int)llvm_ctpop_i32(-594093059)); printf("%d\n", llvm_expect_i32(x % 27, 3)); @@ -1286,6 +1340,7 @@ c5,de,15,8a 23,21 40,10 5,4 +22 13 72057594037927936 ''') @@ -5095,7 +5150,7 @@ def process(filename): 0 0 0 - 0 + -0 1 1 1 @@ -5253,6 +5308,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> @@ -5739,6 +5850,30 @@ def process(filename): self.emcc_args += ['--embed-file', 'file_with_byte_234.txt'] self.do_run(src, '*234\n') + def test_fgets_eol(self): + if self.emcc_args is None: return self.skip('requires emcc') + src = r''' + #include <stdio.h> + char buf[32]; + int main() + { + char *r = "SUCCESS"; + FILE *f = fopen("eol.txt", "r"); + while (fgets(buf, 32, f) != NULL) { + if (buf[0] == '\0') { + r = "FAIL"; + break; + } + } + printf("%s\n", r); + fclose(f); + return 0; + } + ''' + open('eol.txt', 'wb').write('\n') + self.emcc_args += ['--embed-file', 'eol.txt'] + self.do_run(src, 'SUCCESS\n') + def test_folders(self): add_pre_run = ''' def process(filename): @@ -6077,8 +6212,6 @@ def process(filename): self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run_and_checks) def test_utf(self): - if self.emcc_args and 'UTF_STRING_SUPPORT=0' in self.emcc_args: return self.skip('need utf support') - self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well Settings.EXPORTED_FUNCTIONS = ['_main', '_malloc'] @@ -7285,6 +7418,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 @@ -7889,7 +8024,8 @@ def process(filename): 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 = ''' @@ -8064,6 +8200,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, [{ @@ -8084,6 +8221,7 @@ def process(filename): c2.virtualFunc(); // original should remain the same Module.Child2.prototype.runVirtualFunc(c2); c2.virtualFunc2(); +''') + ''' Module.print('*ok*'); \'\'\' @@ -8122,7 +8260,7 @@ Child2:9 *static* *virtualf* *virtualf* -*virtualf2* +*virtualf2*''' + ('' if Settings.ASM_JS else ''' Parent:9 Child2:9 *js virtualf replacement* @@ -8130,13 +8268,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 = ''' @@ -8753,7 +8892,7 @@ TT = %s # asm.js exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])') - exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1", "-s", "UTF_STRING_SUPPORT=0"])') + exec('asm2g = make_run("asm2g", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1", "-g", "-s", "ASSERTIONS=1"])') # Make custom runs with various options for compiler, quantum, embetter, typed_arrays, llvm_opts in [ @@ -9290,7 +9429,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; }" @@ -9919,6 +10058,7 @@ f.close() (path_from_root('tools', 'test-js-optimizer-asm-last.js'), open(path_from_root('tools', 'test-js-optimizer-asm-last-output.js')).read(), ['asm', 'last']), ]: + print input output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0] self.assertIdentical(expected, output.replace('\r\n', '\n').replace('\n\n', '\n')) @@ -9935,13 +10075,19 @@ f.close() try: os.environ['EMCC_DEBUG'] = '1' for asm, linkable, chunks, js_chunks in [ - (0, 0, 3, 2), (0, 1, 4, 4), - (1, 0, 3, 2), (1, 1, 4, 5) + (0, 0, 3, 2), (0, 1, 3, 4), + (1, 0, 3, 2), (1, 1, 3, 4) ]: 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() - assert 'phase 2 working on %d chunks' %chunks in err, err - assert 'splitting up js optimization into %d chunks' % js_chunks in err, err + 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() + ok = False + for c in range(chunks, chunks+2): + ok = ok or ('phase 2 working on %d chunks' % c in err) + assert ok, err + ok = False + for c in range(js_chunks, js_chunks+2): + ok = ok or ('splitting up js optimization into %d chunks' % c in err) + assert ok, err finally: del os.environ['EMCC_DEBUG'] @@ -11279,6 +11425,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']) @@ -12009,7 +12159,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')] 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.js b/tools/js-optimizer.js index 48ab5a1f..5ede0ce8 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -2287,19 +2287,16 @@ function minifyGlobals(ast) { function prepDotZero(ast) { traverse(ast, function(node, type) { if (type == 'unary-prefix' && node[1] == '+') { - if (node[2][0] == 'num') { + if (node[2][0] == 'num' || + (node[2][0] == 'unary-prefix' && node[2][1] == '-' && node[2][2][0] == 'num')) { return ['call', ['name', 'DOT$ZERO'], [node[2]]]; - } else if (node[2][0] == 'unary-prefix' && node[2][1] == '-' && node[2][2][0] == 'num') { - node[2][2][1] = -node[2][2][1]; - return ['call', ['name', 'DOT$ZERO'], [node[2][2]]]; } } }); } function fixDotZero(js) { - return js.replace(/DOT\$ZERO\(((0x)?[-+]?[0-9a-f]*\.?[0-9]+([eE][-+]?[0-9]+)?)\)/g, function(m, num) { - if (num.substr(0, 2) == '0x') { - if (num[2] == '-') num = '-0x' + num.substr(3); // uglify generates 0x-8000 for some reason + return js.replace(/DOT\$ZERO\(([-+]?(0x)?[0-9a-f]*\.?[0-9]+([eE][-+]?[0-9]+)?)\)/g, function(m, num) { + if (num.substr(0, 2) == '0x' || num.substr(0, 3) == '-0x') { return eval(num) + '.0'; } if (num.indexOf('.') >= 0) return num; diff --git a/tools/shared.py b/tools/shared.py index 81a8e053..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: |