summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemscripten.py4
-rw-r--r--src/jsifier.js11
-rw-r--r--src/library.js402
-rw-r--r--src/library_browser.js54
-rw-r--r--src/library_gl.js109
-rw-r--r--src/library_openal.js154
-rw-r--r--src/library_sdl.js19
-rw-r--r--src/parseTools.js4
-rw-r--r--src/preamble.js48
-rw-r--r--src/settings.js16
-rw-r--r--src/shell.html8
-rw-r--r--system/include/libc/ctype.h44
-rw-r--r--tests/cases/alignedunaligned.ll6
-rw-r--r--tests/cases/phicubed.ll29
-rw-r--r--tests/cases/storestruct.ll5
-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.c241
-rw-r--r--tests/gl_ps_strides.pngbin0 -> 98713 bytes
-rwxr-xr-xtests/runner.py181
-rwxr-xr-xtools/bindings_generator.py5
-rw-r--r--tools/js-optimizer.js11
-rw-r--r--tools/shared.py2
24 files changed, 977 insertions, 377 deletions
diff --git a/AUTHORS b/AUTHORS
index 0eb8f7df..0fa41dd2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
new file mode 100644
index 00000000..5b49af36
--- /dev/null
+++ b/tests/gl_ps_strides.png
Binary files differ
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: