summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc3
-rwxr-xr-xemscripten.py3
-rw-r--r--src/analyzer.js36
-rw-r--r--src/jsifier.js11
-rw-r--r--src/library.js484
-rw-r--r--src/library_browser.js31
-rw-r--r--src/library_gl.js10
-rw-r--r--src/library_sdl.js118
-rw-r--r--src/parseTools.js8
-rw-r--r--src/preamble.js5
-rw-r--r--src/runtime.js14
-rw-r--r--src/settings.js3
-rw-r--r--system/include/libc/sys/stat.h3
-rw-r--r--system/include/libc/sys/types.h4
-rw-r--r--tests/cases/i32_mem.ll23
-rw-r--r--tests/cases/i32_mem.txt2
-rw-r--r--tests/cases/zeroembedded.ll23
-rw-r--r--tests/cases/zeroembedded.txt1
-rw-r--r--tests/glgetattachedshaders.c93
-rwxr-xr-xtests/runner.py293
-rw-r--r--tests/sdl_audio.c29
-rw-r--r--tests/stat/output.txt202
-rw-r--r--tests/stat/src.c242
-rw-r--r--tests/stat/test_chmod.c153
-rw-r--r--tests/stat/test_mknod.c96
-rw-r--r--tests/stat/test_stat.c167
-rw-r--r--tools/find_bigfuncs.py7
-rw-r--r--tools/js-optimizer.js194
-rw-r--r--tools/js_optimizer.py13
-rw-r--r--tools/test-js-optimizer-asm-outline1-output.js468
-rw-r--r--tools/test-js-optimizer-asm-outline1.js29
-rw-r--r--tools/test-js-optimizer-asm-outline2-output.js239
-rw-r--r--tools/test-js-optimizer-asm-outline3-output.js28
-rw-r--r--tools/test-js-optimizer-asm-outline3.js30
34 files changed, 2090 insertions, 975 deletions
diff --git a/emcc b/emcc
index bd6350a5..91b109b6 100755
--- a/emcc
+++ b/emcc
@@ -302,6 +302,9 @@ Options that are modified or new in %s include:
your main compiled code (or run it before in
some other way).
+ For more docs on the options --preload-file
+ accepts, see https://github.com/kripken/emscripten/wiki/Filesystem-Guide
+
--compression <codec> Compress both the compiled code and embedded/
preloaded files. <codec> should be a triple,
diff --git a/emscripten.py b/emscripten.py
index 3e3538e9..ab68fcaa 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -291,8 +291,9 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None,
indexed_functions.add(key)
if settings.get('ASM_JS'):
export_bindings = settings['EXPORT_BINDINGS']
+ export_all = settings['EXPORT_ALL']
for key in curr_forwarded_json['Functions']['implementedFunctions'].iterkeys():
- if key in all_exported_functions or (export_bindings and key.startswith('_emscripten_bind')):
+ if key in all_exported_functions or export_all 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/analyzer.js b/src/analyzer.js
index 1d32d7fc..b1f0b585 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -502,18 +502,38 @@ function analyzer(data, sidePass) {
{ intertype: 'value', ident: j.toString(), type: 'i32' }
]
});
- var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits
- toAdd.push({
+ var newItem = {
intertype: 'load',
assignTo: element.ident,
- pointerType: actualSizeType + '*',
- valueType: actualSizeType,
- type: actualSizeType, // XXX why is this missing from intertyper?
- pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' },
+ pointerType: 'i32*',
+ valueType: 'i32',
+ type: 'i32',
+ pointer: { intertype: 'value', ident: tempVar, type: 'i32*' },
ident: tempVar,
- pointerType: actualSizeType + '*',
align: value.align
- });
+ };
+ var newItem2 = null;
+ // The last one may be smaller than 32 bits
+ if (element.bits < 32) {
+ newItem.assignTo += '$preadd$';
+ newItem2 = {
+ intertype: 'mathop',
+ op: 'and',
+ assignTo: element.ident,
+ type: 'i32',
+ params: [{
+ intertype: 'value',
+ type: 'i32',
+ ident: newItem.assignTo
+ }, {
+ intertype: 'value',
+ type: 'i32',
+ ident: (0xffffffff >>> (32 - element.bits)).toString()
+ }],
+ };
+ }
+ toAdd.push(newItem);
+ if (newItem2) toAdd.push(newItem2);
j++;
});
Types.needAnalysis['[0 x i32]'] = 0;
diff --git a/src/jsifier.js b/src/jsifier.js
index 30cea99b..b377202d 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -1211,7 +1211,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// in an assignment
var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST);
var phiSets = calcPhiSets(item);
- var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone);
+ var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true);
var ret;
@@ -1368,7 +1368,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return ret;
});
- function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn) {
+ function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
@@ -1433,7 +1433,7 @@ function JSify(data, functionsOnly, givenFunctions) {
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
if (ASM_JS) {
- if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || funcData.setjmpTable) {
+ if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || funcData.setjmpTable) {
args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
} else {
args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
@@ -1522,7 +1522,8 @@ function JSify(data, functionsOnly, givenFunctions) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
- if (!byPointerForced && !funcData.setjmpTable) {
+ var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke;
+ if (functionTableCall) {
// normal asm function pointer call
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
Functions.neededTables[sig] = 1;
@@ -1537,7 +1538,7 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)';
}
- if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
+ if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']';
}
var ret = callIdent + '(' + args.join(', ') + ')';
diff --git a/src/library.js b/src/library.js
index a41c8105..e650a545 100644
--- a/src/library.js
+++ b/src/library.js
@@ -559,25 +559,28 @@ LibraryManager.library = {
};
}
var utf8 = new Runtime.UTF8Processor();
- function simpleOutput(val) {
- if (val === null || val === {{{ charCode('\n') }}}) {
- output.printer(output.buffer.join(''));
- output.buffer = [];
- } else {
- output.buffer.push(utf8.processCChar(val));
- }
+ function createSimpleOutput() {
+ var fn = function (val) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
+ fn.printer(fn.buffer.join(''));
+ fn.buffer = [];
+ } else {
+ fn.buffer.push(utf8.processCChar(val));
+ }
+ };
+ return fn;
}
if (!output) {
stdoutOverridden = false;
- output = simpleOutput;
+ output = createSimpleOutput();
}
if (!output.printer) output.printer = Module['print'];
if (!output.buffer) output.buffer = [];
if (!error) {
stderrOverridden = false;
- error = simpleOutput;
+ error = createSimpleOutput();
}
- if (!error.printer) error.printer = Module['print'];
+ if (!error.printer) error.printer = Module['printErr'];
if (!error.buffer) error.buffer = [];
// Create the temporary folder, if not already created
@@ -1045,27 +1048,45 @@ LibraryManager.library = {
mknod: function(path, mode, dev) {
// int mknod(const char *path, mode_t mode, dev_t dev);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mknod.html
- if (dev !== 0 || !(mode & 0xC000)) { // S_IFREG | S_IFDIR.
- // Can't create devices or pipes through mknod().
+ path = Pointer_stringify(path);
+ var fmt = (mode & {{{ cDefine('S_IFMT') }}});
+ if (fmt !== {{{ cDefine('S_IFREG') }}} && fmt !== {{{ cDefine('S_IFCHR') }}} &&
+ fmt !== {{{ cDefine('S_IFBLK') }}} && fmt !== {{{ cDefine('S_IFIFO') }}} &&
+ fmt !== {{{ cDefine('S_IFSOCK') }}}) {
+ // not valid formats for mknod
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
- } else {
- var properties = {contents: [], isFolder: Boolean(mode & 0x4000)}; // S_IFDIR.
- path = FS.analyzePath(Pointer_stringify(path));
- try {
- FS.createObject(path.parentObject, path.name, properties,
- mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
- return 0;
- } catch (e) {
- return -1;
- }
+ }
+ if (fmt === {{{ cDefine('S_IFCHR') }}} || fmt === {{{ cDefine('S_IFBLK') }}} ||
+ fmt === {{{ cDefine('S_IFIFO') }}} || fmt === {{{ cDefine('S_IFSOCK') }}}) {
+ // not supported currently
+ ___setErrNo(ERRNO_CODES.EPERM);
+ return -1;
+ }
+ path = FS.analyzePath(path);
+ var properties = { contents: [], isFolder: false }; // S_IFDIR.
+ try {
+ FS.createObject(path.parentObject, path.name, properties,
+ mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
+ return 0;
+ } catch (e) {
+ return -1;
}
},
mkdir__deps: ['mknod'],
mkdir: function(path, mode) {
// int mkdir(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html
- return _mknod(path, 0x4000 | (mode & 0x180), 0); // S_IFDIR, S_IRUSR | S_IWUSR.
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path);
+ var properties = { contents: [], isFolder: true };
+ try {
+ FS.createObject(path.parentObject, path.name, properties,
+ mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR.
+ return 0;
+ } catch (e) {
+ return -1;
+ }
},
mkfifo__deps: ['__setErrNo', '$ERRNO_CODES'],
mkfifo: function(path, mode) {
@@ -1079,10 +1100,13 @@ LibraryManager.library = {
return -1;
},
chmod__deps: ['$FS'],
- chmod: function(path, mode) {
+ chmod: function(path, mode, dontResolveLastLink) {
// int chmod(const char *path, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/chmod.html
- var obj = FS.findObject(Pointer_stringify(path));
+ // NOTE: dontResolveLastLink is a shortcut for lchmod(). It should never be
+ // used in client code.
+ path = typeof path !== 'string' ? Pointer_stringify(path) : path;
+ var obj = FS.findObject(path, dontResolveLastLink);
if (obj === null) return -1;
obj.read = mode & 0x100; // S_IRUSR.
obj.write = mode & 0x80; // S_IWUSR.
@@ -1093,15 +1117,16 @@ LibraryManager.library = {
fchmod: function(fildes, mode) {
// int fchmod(int fildes, mode_t mode);
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html
- if (!FS.streams[fildes]) {
+ var stream = FS.streams[fildes];
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
- } else {
- var pathArray = intArrayFromString(FS.streams[fildes].path);
- return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode);
}
+ return _chmod(stream.path, mode);
+ },
+ lchmod: function(path, mode) {
+ return _chmod(path, mode, true);
},
- lchmod: function() { throw 'TODO: lchmod' },
umask__deps: ['$FS'],
umask: function(newMask) {
@@ -2575,7 +2600,7 @@ LibraryManager.library = {
if (maxx != sub) maxx = 0;
}
if (maxx) {
- var argPtr = HEAP32[(varargs + argIndex)>>2];
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
argIndex += Runtime.getAlignSize('void*', null, true);
fields++;
for (var i = 0; i < maxx; i++) {
@@ -6243,15 +6268,345 @@ LibraryManager.library = {
return -1;
},
- strftime: function(s, maxsize, format, timeptr) {
+ _MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+ _MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
+
+ _isLeapYear: function(year) {
+ return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
+ },
+
+ _arraySum: function(array, index) {
+ var sum = 0;
+ for (var i = 0; i <= index; sum += array[i++]);
+ return sum;
+ },
+
+ _addDays__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP', '_MONTH_DAYS_REGULAR'],
+ _addDays: function(date, days) {
+ var newDate = new Date(date.getTime());
+ while(days > 0) {
+ var leap = __isLeapYear(newDate.getFullYear());
+ var currentMonth = newDate.getMonth();
+ var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
+
+ if (days > daysInCurrentMonth-newDate.getDate()) {
+ // we spill over to next month
+ days -= (daysInCurrentMonth-newDate.getDate()+1);
+ newDate.setDate(1);
+ if (currentMonth < 11) {
+ newDate.setMonth(currentMonth+1)
+ } else {
+ newDate.setMonth(0);
+ newDate.setFullYear(newDate.getFullYear()+1);
+ }
+ } else {
+ // we stay in current month
+ newDate.setDate(newDate.getDate()+days);
+ return newDate;
+ }
+ }
+
+ return newDate;
+ },
+
+ strftime__deps: ['__tm_struct_layout', '_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
+ strftime: function(s, maxsize, format, tm) {
// size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
- // TODO: Implement.
- return 0;
+
+ var date = {
+ tm_sec: {{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32') }}},
+ tm_min: {{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32') }}},
+ tm_hour: {{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32') }}},
+ tm_mday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32') }}},
+ tm_mon: {{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32') }}},
+ tm_year: {{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32') }}},
+ tm_wday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_wday', 'i32') }}},
+ tm_yday: {{{ makeGetValue('tm', '___tm_struct_layout.tm_yday', 'i32') }}},
+ tm_isdst: {{{ makeGetValue('tm', '___tm_struct_layout.tm_isdst', 'i32') }}}
+ };
+
+ var pattern = Pointer_stringify(format);
+
+ // expand format
+ var EXPANSION_RULES_1 = {
+ '%c': '%a %b %d %H:%M:%S %Y', // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug 3 14:02:01 2013
+ '%D': '%m/%d/%y', // Equivalent to %m / %d / %y
+ '%F': '%Y-%m-%d', // Equivalent to %Y - %m - %d
+ '%h': '%b', // Equivalent to %b
+ '%r': '%I:%M:%S %p', // Replaced by the time in a.m. and p.m. notation
+ '%R': '%H:%M', // Replaced by the time in 24-hour notation
+ '%T': '%H:%M:%S', // Replaced by the time
+ '%x': '%m/%d/%y', // Replaced by the locale's appropriate date representation
+ '%X': '%H:%M:%S', // Replaced by the locale's appropriate date representation
+ };
+ for (var rule in EXPANSION_RULES_1) {
+ pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]);
+ }
+
+ var WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+ var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
+
+ var leadingSomething = function(value, digits, character) {
+ var str = typeof value === 'number' ? value.toString() : (value || '');
+ while (str.length < digits) {
+ str = character[0]+str;
+ }
+ return str;
+ };
+
+ var leadingNulls = function(value, digits) {
+ return leadingSomething(value, digits, '0');
+ };
+
+ var compareByDay = function(date1, date2) {
+ var sgn = function(value) {
+ return value < 0 ? -1 : (value > 0 ? 1 : 0);
+ };
+
+ var compare;
+ if ((compare = sgn(date1.getFullYear()-date2.getFullYear())) === 0) {
+ if ((compare = sgn(date1.getMonth()-date2.getMonth())) === 0) {
+ compare = sgn(date1.getDate()-date2.getDate());
+ }
+ }
+ return compare;
+ };
+
+ var getFirstWeekStartDate = function(janFourth) {
+ switch (janFourth.getDay()) {
+ case 0: // Sunday
+ return new Date(janFourth.getFullYear()-1, 11, 29);
+ case 1: // Monday
+ return janFourth;
+ case 2: // Tuesday
+ return new Date(janFourth.getFullYear(), 0, 3);
+ case 3: // Wednesday
+ return new Date(janFourth.getFullYear(), 0, 2);
+ case 4: // Thursday
+ return new Date(janFourth.getFullYear(), 0, 1);
+ case 5: // Friday
+ return new Date(janFourth.getFullYear()-1, 11, 31);
+ case 6: // Saturday
+ return new Date(janFourth.getFullYear()-1, 11, 30);
+ }
+ };
+
+ var getWeekBasedYear = function(date) {
+ var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+ var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
+ var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4);
+
+ var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+ var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+ if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
+ // this date is after the start of the first week of this year
+ if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
+ return thisDate.getFullYear()+1;
+ } else {
+ return thisDate.getFullYear();
+ }
+ } else {
+ return thisDate.getFullYear()-1;
+ }
+ };
+
+ var EXPANSION_RULES_2 = {
+ '%a': function(date) {
+ return WEEKDAYS[date.tm_wday].substring(0,3);
+ },
+ '%A': function(date) {
+ return WEEKDAYS[date.tm_wday];
+ },
+ '%b': function(date) {
+ return MONTHS[date.tm_mon].substring(0,3);
+ },
+ '%B': function(date) {
+ return MONTHS[date.tm_mon];
+ },
+ '%C': function(date) {
+ var year = date.tm_year+1900;
+ return leadingNulls(Math.floor(year/100),2);
+ },
+ '%d': function(date) {
+ return leadingNulls(date.tm_mday, 2);
+ },
+ '%e': function(date) {
+ return leadingSomething(date.tm_mday, 2, ' ');
+ },
+ '%g': function(date) {
+ // %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year.
+ // In this system, weeks begin on a Monday and week 1 of the year is the week that includes
+ // January 4th, which is also the week that includes the first Thursday of the year, and
+ // is also the first week that contains at least four days in the year.
+ // If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of
+ // the last week of the preceding year; thus, for Saturday 2nd January 1999,
+ // %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th,
+ // or 31st is a Monday, it and any following days are part of week 1 of the following year.
+ // Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
+
+ return getWeekBasedYear(date).toString().substring(2);
+ },
+ '%G': function(date) {
+ return getWeekBasedYear(date);
+ },
+ '%H': function(date) {
+ return leadingNulls(date.tm_hour, 2);
+ },
+ '%I': function(date) {
+ return leadingNulls(date.tm_hour < 13 ? date.tm_hour : date.tm_hour-12, 2);
+ },
+ '%j': function(date) {
+ // Day of the year (001-366)
+ return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3);
+ },
+ '%m': function(date) {
+ return leadingNulls(date.tm_mon+1, 2);
+ },
+ '%M': function(date) {
+ return leadingNulls(date.tm_min, 2);
+ },
+ '%n': function() {
+ return '\n';
+ },
+ '%p': function(date) {
+ if (date.tm_hour > 0 && date.tm_hour < 13) {
+ return 'AM';
+ } else {
+ return 'PM';
+ }
+ },
+ '%S': function(date) {
+ return leadingNulls(date.tm_sec, 2);
+ },
+ '%t': function() {
+ return '\t';
+ },
+ '%u': function(date) {
+ var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+ return day.getDay() || 7;
+ },
+ '%U': function(date) {
+ // Replaced by the week number of the year as a decimal number [00,53].
+ // The first Sunday of January is the first day of week 1;
+ // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+ var janFirst = new Date(date.tm_year+1900, 0, 1);
+ var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7-janFirst.getDay());
+ var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+ // is target date after the first Sunday?
+ if (compareByDay(firstSunday, endDate) < 0) {
+ // calculate difference in days between first Sunday and endDate
+ var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+ var firstSundayUntilEndJanuary = 31-firstSunday.getDate();
+ var days = firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+ return leadingNulls(Math.ceil(days/7), 2);
+ }
+
+ return compareByDay(firstSunday, janFirst) === 0 ? '01': '00';
+ },
+ '%V': function(date) {
+ // Replaced by the week number of the year (Monday as the first day of the week)
+ // as a decimal number [01,53]. If the week containing 1 January has four
+ // or more days in the new year, then it is considered week 1.
+ // Otherwise, it is the last week of the previous year, and the next week is week 1.
+ // Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
+ var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
+ var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
+
+ var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
+ var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
+
+ var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
+
+ if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
+ // if given date is before this years first week, then it belongs to the 53rd week of last year
+ return '53';
+ }
+
+ if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
+ // if given date is after next years first week, then it belongs to the 01th week of next year
+ return '01';
+ }
+
+ // given date is in between CW 01..53 of this calendar year
+ var daysDifference;
+ if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
+ // first CW of this year starts last year
+ daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
+ } else {
+ // first CW of this year starts this year
+ daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
+ }
+ return leadingNulls(Math.ceil(daysDifference/7), 2);
+ },
+ '%w': function(date) {
+ var day = new Date(date.tm_year+1900, date.tm_mon+1, date.tm_mday, 0, 0, 0, 0);
+ return day.getDay();
+ },
+ '%W': function(date) {
+ // Replaced by the week number of the year as a decimal number [00,53].
+ // The first Monday of January is the first day of week 1;
+ // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+ var janFirst = new Date(date.tm_year, 0, 1);
+ var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7-janFirst.getDay()+1);
+ var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
+
+ // is target date after the first Monday?
+ if (compareByDay(firstMonday, endDate) < 0) {
+ var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
+ var firstMondayUntilEndJanuary = 31-firstMonday.getDate();
+ var days = firstMondayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
+ return leadingNulls(Math.ceil(days/7), 2);
+ }
+ return compareByDay(firstMonday, janFirst) === 0 ? '01': '00';
+ },
+ '%y': function(date) {
+ // Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
+ return (date.tm_year+1900).toString().substring(2);
+ },
+ '%Y': function(date) {
+ // Replaced by the year as a decimal number (for example, 1997). [ tm_year]
+ return date.tm_year+1900;
+ },
+ '%z': function(date) {
+ // Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ),
+ // or by no characters if no timezone is determinable.
+ // For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich).
+ // If tm_isdst is zero, the standard time offset is used.
+ // If tm_isdst is greater than zero, the daylight savings time offset is used.
+ // If tm_isdst is negative, no characters are returned.
+ // FIXME: we cannot determine time zone (or can we?)
+ return '';
+ },
+ '%Z': function(date) {
+ // Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [ tm_isdst]
+ // FIXME: we cannot determine time zone (or can we?)
+ return '';
+ },
+ '%%': function() {
+ return '%';
+ }
+ };
+ for (var rule in EXPANSION_RULES_2) {
+ if (pattern.indexOf(rule) >= 0) {
+ pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date));
+ }
+ }
+
+ var bytes = intArrayFromString(pattern, false);
+ if (bytes.length > maxsize) {
+ return 0;
+ }
+
+ writeArrayToMemory(bytes, s);
+ return bytes.length-1;
},
strftime_l: 'strftime', // no locale support yet
- strptime__deps: ['__tm_struct_layout'],
+ strptime__deps: ['__tm_struct_layout', '_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP'],
strptime: function(buf, format, tm) {
// char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html
@@ -6307,46 +6662,9 @@ LibraryManager.library = {
};
var MONTH_NUMBERS = {JAN: 0, FEB: 1, MAR: 2, APR: 3, MAY: 4, JUN: 5, JUL: 6, AUG: 7, SEP: 8, OCT: 9, NOV: 10, DEC: 11};
- var MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- var MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
var DAY_NUMBERS_SUN_FIRST = {SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6};
var DAY_NUMBERS_MON_FIRST = {MON: 0, TUE: 1, WED: 2, THU: 3, FRI: 4, SAT: 5, SUN: 6};
- var isLeapYear = function(year) {
- return year%4===0 && (year%100!==0 || year%400===0);
- };
-
- var arraySum = function(array, index) {
- var sum = 0;
- for (var i=0; i<=index; sum += array[i++]);
- return sum;
- };
-
- var addDays = function(date, days) {
- while(days>0) {
- var leap = isLeapYear(date.getFullYear());
- var currentMonth = date.getMonth();
- var daysInCurrentMonth = (leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[currentMonth];
-
- if (days>daysInCurrentMonth-date.getDate()) {
- // we spill over to next month
- days -= (daysInCurrentMonth-date.getDate()+1);
- date.setDate(1);
- if (currentMonth<11) {
- date.setMonth(currentMonth+1)
- } else {
- date.setMonth(0);
- date.setFullYear(date.getFullYear()+1);
- }
- } else {
- // we stay in current month
- date.setDate(date.getDate()+days);
- return date;
- }
- }
- return date;
- };
-
for (var datePattern in DATE_PATTERNS) {
pattern = pattern.replace(datePattern, '('+datePattern+DATE_PATTERNS[datePattern]+')');
}
@@ -6446,10 +6764,10 @@ LibraryManager.library = {
} else if ((value=getMatch('j'))) {
// get day of month from day of year ...
var day = parseInt(value);
- var leapYear = isLeapYear(date.year);
+ var leapYear = __isLeapYear(date.year);
for (var month=0; month<12; ++month) {
- var daysUntilMonth = arraySum(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, month-1);
- if (day<=daysUntilMonth+(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[month]) {
+ var daysUntilMonth = __arraySum(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, month-1);
+ if (day<=daysUntilMonth+(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[month]) {
date.day = day-daysUntilMonth;
}
}
@@ -6468,10 +6786,10 @@ LibraryManager.library = {
var endDate;
if (janFirst.getDay() === 0) {
// Jan 1st is a Sunday, and, hence in the 1st CW
- endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1));
+ endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1));
} else {
// Jan 1st is not a Sunday, and, hence still in the 0th CW
- endDate = addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1));
+ endDate = __addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1));
}
date.day = endDate.getDate();
date.month = endDate.getMonth();
@@ -6487,10 +6805,10 @@ LibraryManager.library = {
var endDate;
if (janFirst.getDay()===1) {
// Jan 1st is a Monday, and, hence in the 1st CW
- endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1));
+ endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1));
} else {
// Jan 1st is not a Monday, and, hence still in the 0th CW
- endDate = addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1));
+ endDate = __addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1));
}
date.day = endDate.getDate();
@@ -6518,7 +6836,7 @@ LibraryManager.library = {
{{{ makeSetValue('tm', '___tm_struct_layout.tm_mon', 'fullDate.getMonth()', 'i32') }}}
{{{ makeSetValue('tm', '___tm_struct_layout.tm_year', 'fullDate.getFullYear()-1900', 'i32') }}}
{{{ makeSetValue('tm', '___tm_struct_layout.tm_wday', 'fullDate.getDay()', 'i32') }}}
- {{{ makeSetValue('tm', '___tm_struct_layout.tm_yday', 'arraySum(isLeapYear(fullDate.getFullYear()) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
+ {{{ makeSetValue('tm', '___tm_struct_layout.tm_yday', '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
{{{ makeSetValue('tm', '___tm_struct_layout.tm_isdst', '0', 'i32') }}}
// we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F
@@ -6635,15 +6953,15 @@ LibraryManager.library = {
// NOTE: These are fake, since we don't support the C device creation API.
// http://www.kernel.org/doc/man-pages/online/pages/man3/minor.3.html
makedev: function(maj, min) {
- return 0;
+ return ((maj) << 8 | (min));
},
gnu_dev_makedev: 'makedev',
major: function(dev) {
- return 0;
+ return ((dev) >> 8);
},
gnu_dev_major: 'major',
minor: function(dev) {
- return 0;
+ return ((dev) & 0xff);
},
gnu_dev_minor: 'minor',
diff --git a/src/library_browser.js b/src/library_browser.js
index 7f79b2bd..0db2cc44 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -70,18 +70,6 @@ mergeInto(LibraryManager.library, {
// (possibly modified) data. For example, a plugin might decompress a file, or it
// might create some side data structure for use later (like an Image element, etc.).
- function getMimetype(name) {
- return {
- 'jpg': 'image/jpeg',
- 'jpeg': 'image/jpeg',
- 'png': 'image/png',
- 'bmp': 'image/bmp',
- 'ogg': 'audio/ogg',
- 'wav': 'audio/wav',
- 'mp3': 'audio/mpeg'
- }[name.substr(name.lastIndexOf('.')+1)];
- }
-
var imagePlugin = {};
imagePlugin['canHandle'] = function(name) {
return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name);
@@ -90,10 +78,10 @@ mergeInto(LibraryManager.library, {
var b = null;
if (Browser.hasBlobConstructor) {
try {
- b = new Blob([byteArray], { type: getMimetype(name) });
+ b = new Blob([byteArray], { type: Browser.getMimetype(name) });
if (b.size !== byteArray.length) { // Safari bug #118630
// Safari's Blob can only take an ArrayBuffer
- b = new Blob([(new Uint8Array(byteArray)).buffer], { type: getMimetype(name) });
+ b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) });
}
} catch(e) {
Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
@@ -148,7 +136,7 @@ mergeInto(LibraryManager.library, {
}
if (Browser.hasBlobConstructor) {
try {
- var b = new Blob([byteArray], { type: getMimetype(name) });
+ var b = new Blob([byteArray], { type: Browser.getMimetype(name) });
} catch(e) {
return fail();
}
@@ -391,6 +379,18 @@ mergeInto(LibraryManager.library, {
}, timeout);
},
+ getMimetype: function(name) {
+ return {
+ 'jpg': 'image/jpeg',
+ 'jpeg': 'image/jpeg',
+ 'png': 'image/png',
+ 'bmp': 'image/bmp',
+ 'ogg': 'audio/ogg',
+ 'wav': 'audio/wav',
+ 'mp3': 'audio/mpeg'
+ }[name.substr(name.lastIndexOf('.')+1)];
+ },
+
getUserMedia: function(func) {
if(!window.getUserMedia) {
window.getUserMedia = navigator['getUserMedia'] ||
@@ -399,6 +399,7 @@ mergeInto(LibraryManager.library, {
window.getUserMedia(func);
},
+
getMovementX: function(event) {
return event['movementX'] ||
event['mozMovementX'] ||
diff --git a/src/library_gl.js b/src/library_gl.js
index 959773bc..d0f1a692 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -372,6 +372,12 @@ var LibraryGL = {
case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS
{{{ makeSetValue('p', '0', '0', 'i32') }}};
return;
+ case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS
+ // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be queried for length),
+ // so implement it ourselves to allow C++ GLES2 code get the length.
+ var formats = Module.ctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/);
+ {{{ makeSetValue('p', '0', 'formats.length', 'i32') }}};
+ return;
}
var result = Module.ctx.getParameter(name_);
switch (typeof(result)) {
@@ -1076,7 +1082,9 @@ var LibraryGL = {
}
{{{ makeSetValue('count', '0', 'len', 'i32') }}};
for (var i = 0; i < len; ++i) {
- {{{ makeSetValue('shaders', 'i*4', 'GL.shaders[result[i]]', 'i32') }}};
+ var id = GL.shaders.indexOf(result[i]);
+ assert(id !== -1, 'shader not bound to local id');
+ {{{ makeSetValue('shaders', 'i*4', 'id', 'i32') }}};
}
},
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 9287bd3e..7078aa9d 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -28,6 +28,7 @@ var LibrarySDL = {
// The currently preloaded audio elements ready to be played
audios: [null],
+ rwops: [null],
// The currently playing audio element. There's only one music track.
music: {
audio: null,
@@ -1228,9 +1229,24 @@ var LibrarySDL = {
return flags; // We support JPG, PNG, TIF because browsers do
},
- IMG_Load__deps: ['SDL_LockSurface'],
- IMG_Load: function(filename) {
- filename = FS.standardizePath(Pointer_stringify(filename));
+ IMG_Load_RW__deps: ['SDL_LockSurface'],
+ IMG_Load_RW: function(rwopsID, freesrc) {
+ var rwops = SDL.rwops[rwopsID];
+
+ if (rwops === undefined) {
+ return 0;
+ }
+
+ var filename = rwops.filename;
+
+ if (filename === undefined) {
+ Runtime.warnOnce('Only file names that have been preloaded are supported for IMG_Load_RW.');
+ // TODO. Support loading image data from embedded files, similarly to Mix_LoadWAV_RW
+ // TODO. Support loading image data from byte arrays, similarly to Mix_LoadWAV_RW
+ return 0;
+ }
+
+ filename = FS.standardizePath(filename);
if (filename[0] == '/') {
// Convert the path to relative
filename = filename.substr(1);
@@ -1262,8 +1278,14 @@ var LibrarySDL = {
return surf;
},
SDL_LoadBMP: 'IMG_Load',
- SDL_LoadBMP_RW: 'IMG_Load',
- IMG_Load_RW: 'IMG_Load',
+ SDL_LoadBMP_RW: 'IMG_Load_RW',
+ IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile', 'SDL_FreeRW'],
+ IMG_Load: function(filename){
+ var rwops = _SDL_RWFromFile(filename);
+ var result = _IMG_Load_RW(rwops);
+ _SDL_FreeRW(rwops);
+ return result;
+ },
// SDL_Audio
@@ -1399,22 +1421,62 @@ var LibrarySDL = {
return 0; // error
},
- Mix_LoadWAV_RW: function(filename, freesrc) {
- filename = FS.standardizePath(Pointer_stringify(filename));
- var raw = Module["preloadedAudios"][filename];
- if (!raw) {
- if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!');
- Runtime.warnOnce('Cannot find preloaded audio ' + filename);
+ Mix_LoadWAV_RW: function(rwopsID, freesrc) {
+ var rwops = SDL.rwops[rwopsID];
+
+ if (rwops === undefined)
+ return 0;
+
+ var filename = '';
+ var audio;
+ var bytes;
+
+ if (rwops.filename !== undefined) {
+ filename = rwops.filename;
+ filename = FS.standardizePath(filename);
+ var raw = Module["preloadedAudios"][filename];
+ if (!raw) {
+ if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!');
+ Runtime.warnOnce('Cannot find preloaded audio ' + filename);
+
+ // see if we can read the file-contents from the in-memory FS
+ var fileObject = FS.findObject(filename);
+
+ if (fileObject === null) Module.printErr('Couldn\'t find file for: ' + filename);
+
+ // We found the file. Load the contents
+ if (fileObject && !fileObject.isFolder && fileObject.read) {
+ bytes = fileObject.contents
+ } else {
+ return 0;
+ }
+ }
+ if (Module['freePreloadedMediaOnUse']) {
+ Module["preloadedAudios"][filename] = null;
+ }
+ audio = raw;
+ }
+ else if (rwops.bytes !== undefined) {
+ bytes = HEAPU8.subarray(rwops.bytes, rwops.bytes + rwops.count);
+ }
+ else {
return 0;
}
- if (Module['freePreloadedMediaOnUse']) {
- Module["preloadedAudios"][filename] = null;
+
+ // Here, we didn't find a preloaded audio but we either were passed a filepath for
+ // which we loaded bytes, or we were passed some bytes
+ if (audio === undefined && bytes) {
+ var blob = new Blob([new Uint8Array(bytes)], {type: rwops.mimetype});
+ var url = URL.createObjectURL(blob);
+ audio = new Audio();
+ audio.src = url;
}
+
var id = SDL.audios.length;
// Keep the loaded audio in the audio arrays, ready for playback
SDL.audios.push({
source: filename,
- audio: raw
+ audio: audio
});
return id;
},
@@ -1574,8 +1636,14 @@ var LibrarySDL = {
return SDL.setGetVolume(SDL.music, volume);
},
- Mix_LoadMUS: 'Mix_LoadWAV_RW',
Mix_LoadMUS_RW: 'Mix_LoadWAV_RW',
+ Mix_LoadMUS__deps: ['Mix_LoadMUS_RW', 'SDL_RWFromFile', 'SDL_FreeRW'],
+ Mix_LoadMUS: function(filename) {
+ var rwops = _SDL_RWFromFile(filename);
+ var result = _Mix_LoadMUS_RW(rwops);
+ _SDL_FreeRW(rwops);
+ return result;
+ },
Mix_FreeMusic: 'Mix_FreeChunk',
@@ -1978,9 +2046,24 @@ var LibrarySDL = {
// Misc
SDL_InitSubSystem: function(flags) { return 0 },
+ SDL_RWFromConstMem: function(mem, size) {
+ var id = SDL.rwops.length; // TODO: recycle ids when they are null
+ SDL.rwops.push({ bytes: mem, count: size });
+ return id;
+ },
- SDL_RWFromFile: function(filename, mode) {
- return filename; // XXX We just forward the filename
+ SDL_RWFromFile: function(_name, mode) {
+ var id = SDL.rwops.length; // TODO: recycle ids when they are null
+ var name = Pointer_stringify(_name)
+ SDL.rwops.push({ filename: name, mimetype: Browser.getMimetype(name) });
+ return id;
+ },
+
+ SDL_FreeRW: function(rwopsID) {
+ SDL.rwops[rwopsID] = null;
+ while (SDL.rwops.length > 0 && SDL.rwops[SDL.rwops.length-1] === null) {
+ SDL.rwops.pop();
+ }
},
SDL_EnableUNICODE: function(on) {
@@ -2007,7 +2090,6 @@ var LibrarySDL = {
SDL_GetThreadID: function() { throw 'SDL_GetThreadID' },
SDL_ThreadID: function() { throw 'SDL_ThreadID' },
SDL_AllocRW: function() { throw 'SDL_AllocRW: TODO' },
- SDL_FreeRW: function() { throw 'SDL_FreeRW: TODO' },
SDL_CondBroadcast: function() { throw 'SDL_CondBroadcast: TODO' },
SDL_CondWaitTimeout: function() { throw 'SDL_CondWaitTimeout: TODO' },
SDL_WM_IconifyWindow: function() { throw 'SDL_WM_IconifyWindow TODO' },
diff --git a/src/parseTools.js b/src/parseTools.js
index a5785e27..72166592 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -969,6 +969,12 @@ function generateStructTypes(type) {
}
ret[index++] = type;
} else {
+ if (Runtime.isStructType(type) && type[1] === '0') {
+ // this is [0 x something]. When inside another structure like here, it must be at the end,
+ // and it does nothing
+ assert(i === typeData.fields.length-1);
+ return;
+ }
add(Types.types[type]);
}
var more = (i+1 < typeData.fields.length ? typeData.flatIndexes[i+1] : typeData.flatSize) - (index - start);
@@ -1694,7 +1700,7 @@ function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
}
case 'float': return ['HEAPF32'];
default: {
- throw 'what, exactly, can we do for unknown types in TA2?! ' + new Error().stack;
+ throw 'what, exactly, can we do for unknown types in TA2?! ' + [new Error().stack, ptr, type, allowMultiple, unsigned];
}
}
}
diff --git a/src/preamble.js b/src/preamble.js
index ef34da6b..218e0388 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -784,7 +784,7 @@ Module['writeArrayToMemory'] = writeArrayToMemory;
{{{ reSign }}}
#if PRECISE_I32_MUL
-if (!Math.imul) Math.imul = function(a, b) {
+if (!Math['imul']) Math['imul'] = function(a, b) {
var ah = a >>> 16;
var al = a & 0xffff;
var bh = b >>> 16;
@@ -792,10 +792,11 @@ if (!Math.imul) Math.imul = function(a, b) {
return (al*bl + ((ah*bl + al*bh) << 16))|0;
};
#else
-Math.imul = function(a, b) {
+Math['imul'] = function(a, b) {
return (a*b)|0; // fast but imprecise
};
#endif
+Math.imul = Math['imul'];
// A counter of dependencies for calling run(). If we need to
// do asynchronous work before running, increment this and
diff --git a/src/runtime.js b/src/runtime.js
index 684f11e7..8c2c8f4d 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -201,14 +201,24 @@ var Runtime = {
type.alignSize = 0;
var diffs = [];
var prev = -1;
+ var index = 0;
type.flatIndexes = type.fields.map(function(field) {
+ index++;
var size, alignSize;
if (Runtime.isNumberType(field) || Runtime.isPointerType(field)) {
size = Runtime.getNativeTypeSize(field); // pack char; char; in structs, also char[X]s.
alignSize = Runtime.getAlignSize(field, size);
} else if (Runtime.isStructType(field)) {
- size = Types.types[field].flatSize;
- alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+ if (field[1] === '0') {
+ // this is [0 x something]. When inside another structure like here, it must be at the end,
+ // and it adds no size
+ assert(index === type.fields.length);
+ size = 0;
+ alignSize = type.alignSize || QUANTUM_SIZE;
+ } else {
+ size = Types.types[field].flatSize;
+ alignSize = Runtime.getAlignSize(null, Types.types[field].alignSize);
+ }
} else if (field[0] == 'b') {
// bN, large number field, like a [N x i8]
size = field.substr(1)|0;
diff --git a/src/settings.js b/src/settings.js
index b33ea7b3..b7460cf2 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -243,6 +243,8 @@ var FS_LOG = 0; // Log all FS operations. This is especially helpful when you'r
// a new project and want to see a list of file system operations happening
// so that you can create a virtual file system with all of the required files.
+var USE_OLD_FS = 1; // Switch to toggle the new / old FS code. Currently only used for testing purposes.
+
var USE_BSS = 1; // https://en.wikipedia.org/wiki/.bss
// When enabled, 0-initialized globals are sorted to the end of the globals list,
// enabling us to not explicitly store the initialization value for each 0 byte.
@@ -412,7 +414,6 @@ var DEBUG_TAGS_SHOWING = [];
// metadata
// legalizer
-
// A cached set of defines, generated from the header files. This
// lets the emscripten libc (library.js) see the right values.
// If you the headers or use different ones, you will need to override
diff --git a/system/include/libc/sys/stat.h b/system/include/libc/sys/stat.h
index e2b20187..2285b294 100644
--- a/system/include/libc/sys/stat.h
+++ b/system/include/libc/sys/stat.h
@@ -179,7 +179,8 @@ struct stat64
#endif
int _EXFUN(chmod,( const char *__path, mode_t __mode ));
-int _EXFUN(fchmod,(int __fd, mode_t __mode));
+int _EXFUN(lchmod,( const char *__path, mode_t __mode ));
+int _EXFUN(fchmod,(int __fd, mode_t __mode));
int _EXFUN(fstat,( int __fd, struct stat *__sbuf ));
int _EXFUN(fstat64,( int __fd, struct stat64 *__sbuf )); /* XXX Emscripten */
int _EXFUN(mkdir,( const char *_path, mode_t __mode ));
diff --git a/system/include/libc/sys/types.h b/system/include/libc/sys/types.h
index c36f724c..fe5d552a 100644
--- a/system/include/libc/sys/types.h
+++ b/system/include/libc/sys/types.h
@@ -159,6 +159,10 @@ typedef __gid_t gid_t;
typedef __id_t id_t ; /* can hold a uid_t or pid_t */
#endif
+__int32_t major(__uint32_t _x);
+__int32_t minor(__uint32_t _x);
+dev_t makedev(__uint32_t _major, __uint32_t _minor);
+
#if defined(__XMK__)
typedef signed char pid_t;
#else
diff --git a/tests/cases/i32_mem.ll b/tests/cases/i32_mem.ll
new file mode 100644
index 00000000..e50014ca
--- /dev/null
+++ b/tests/cases/i32_mem.ll
@@ -0,0 +1,23 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c".%x.\0A\00", align 1 ; [#uses=1 type=[5 x i8]*]
+
+define i32 @main() {
+entry:
+ %mem = alloca i32
+ store i32 4279383126, i32* %mem
+ %i24 = bitcast i32* %mem to i24*
+ %load = load i24* %i24, align 4
+ %load32 = zext i24 %load to i32
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %load32)
+ %val_24 = trunc i32 4041265344 to i24
+ store i24 %val_24, i24* %i24, align 4
+ %load32b = load i32* %mem, align 4
+ %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %load32b)
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/cases/i32_mem.txt b/tests/cases/i32_mem.txt
new file mode 100644
index 00000000..683e58e2
--- /dev/null
+++ b/tests/cases/i32_mem.txt
@@ -0,0 +1,2 @@
+.123456.
+.ffe0d0c0.
diff --git a/tests/cases/zeroembedded.ll b/tests/cases/zeroembedded.ll
new file mode 100644
index 00000000..6a4f6073
--- /dev/null
+++ b/tests/cases/zeroembedded.ll
@@ -0,0 +1,23 @@
+; a.ll
+%struct.pypy_str = type { i32, [0 x i8] }
+%struct.pypy_strval = type { i32, [13 x i8] }
+
+%union.pypy_array3_len0u = type { %struct.pypy_array3_len0 }
+%struct.pypy_array3_len0 = type { i32, i32, [0 x i8] }
+
+@pypy_g_strval = global %struct.pypy_strval { i32 13, [13 x i8] c"hello world\0A\00" }
+@pypy_g_strval2 = global %struct.pypy_array3_len0 { i32 13, i32 111, [0 x i8] c"" }
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main(i32 %argc, i8** nocapture %argv) {
+ %waka = alloca %struct.pypy_array3_len0
+ %1 = bitcast %struct.pypy_strval* @pypy_g_strval to %struct.pypy_str*
+ %2 = getelementptr inbounds %struct.pypy_str* %1, i32 1
+ %3 = bitcast %struct.pypy_str* %2 to i8*
+ call i32 (i8*, ...)* @printf(i8* %3)
+ %unneeded = bitcast %struct.pypy_str* %2 to %struct.pypy_array3_len0*
+ call i32 (i8*, ...)* @printf(i8* %3, %struct.pypy_array3_len0* %unneeded)
+ ret i32 0
+}
+
diff --git a/tests/cases/zeroembedded.txt b/tests/cases/zeroembedded.txt
new file mode 100644
index 00000000..3b18e512
--- /dev/null
+++ b/tests/cases/zeroembedded.txt
@@ -0,0 +1 @@
+hello world
diff --git a/tests/glgetattachedshaders.c b/tests/glgetattachedshaders.c
new file mode 100644
index 00000000..303e0f92
--- /dev/null
+++ b/tests/glgetattachedshaders.c
@@ -0,0 +1,93 @@
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void die(const char *msg)
+{
+ printf("%s\n", msg);
+ abort();
+}
+
+static void create_context(void)
+{
+ EGLint num_config;
+ EGLContext g_egl_ctx;
+ EGLDisplay g_egl_dpy;
+ EGLConfig g_config;
+
+ static const EGLint attribute_list[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ static const EGLint context_attributes[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!g_egl_dpy)
+ die("failed to create display");
+
+ if (!eglInitialize(g_egl_dpy, NULL, NULL))
+ die("failed to initialize egl");
+
+ if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config))
+ die("failed to choose config");
+
+ g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, context_attributes);
+ if (!g_egl_ctx)
+ die("failed to create context");
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned i;
+
+ create_context();
+
+ GLuint prog = glCreateProgram();
+ if (glGetError())
+ die("failed to create program");
+
+ GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
+ if (glGetError())
+ die("failed to create vertex shader");
+ glAttachShader(prog, vertex);
+
+ GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ if (glGetError())
+ die("failed to create fragment shader");
+ glAttachShader(prog, fragment);
+
+ GLuint shaders[2];
+ GLsizei count;
+
+ glGetAttachedShaders(prog, 2, &count, shaders);
+ if (glGetError())
+ die("failed to get attached shaders");
+ if (count != 2)
+ die("unknown number of shaders returned");
+ if (shaders[0] == shaders[1])
+ die("returned identical shaders");
+
+ for (i = 0; i < count; i++)
+ {
+ if (shaders[i] == 0)
+ die("returned 0");
+ if (shaders[i] != vertex && shaders[i] != fragment)
+ die("unknown shader returned");
+ }
+
+ int result = 1;
+ REPORT_RESULT();
+
+ return 0;
+}
diff --git a/tests/runner.py b/tests/runner.py
index e34fb63b..15f0070a 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -271,6 +271,8 @@ process(sys.argv[1])
print >> sys.stderr, "[was asm.js'ified]"
elif 'asm.js' in err: # if no asm.js error, then not an odin build
raise Exception("did NOT asm.js'ify")
+ err = '\n'.join(filter(lambda line: 'successfully compiled asm.js code' not in line, err.split('\n')))
+ return err
def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None):
stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us
@@ -286,7 +288,7 @@ process(sys.argv[1])
out = open(stdout, 'r').read()
err = open(stderr, 'r').read()
if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS:
- self.validate_asmjs(err)
+ err = self.validate_asmjs(err)
if output_nicerizer:
ret = output_nicerizer(out, err)
else:
@@ -2967,6 +2969,37 @@ back
self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug
self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...')
+ def test_exception_2(self):
+ if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ src = r'''
+ #include <stdexcept>
+ #include <stdio.h>
+
+ typedef void (*FuncPtr)();
+
+ void ThrowException()
+ {
+ throw std::runtime_error("catch me!");
+ }
+
+ FuncPtr ptr = ThrowException;
+
+ int main()
+ {
+ try
+ {
+ ptr();
+ }
+ catch(...)
+ {
+ printf("Exception caught successfully!\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Exception caught successfully!')
+
def test_white_list_exception(self):
Settings.DISABLE_EXCEPTION_CATCHING = 2
Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
@@ -4029,6 +4062,11 @@ def process(filename):
Settings.EXPORTED_FUNCTIONS = ['_main', '_save_me_aimee']
self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
+ # test EXPORT_ALL
+ Settings.EXPORTED_FUNCTIONS = []
+ Settings.EXPORT_ALL = 1
+ self.do_run(src, 'hello world!\n*100*\n*fivesix*\nmann\n', post_build=check)
+
def test_inlinejs(self):
if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
src = r'''
@@ -5111,6 +5149,162 @@ The current type of b is: 9
'''
self.do_run(src, 'OK')
+ def test_strftime(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ void test(int result, const char* comment, const char* parsed = "") {
+ printf("%d",result);
+ if (!result) {
+ printf("\nERROR: %s (\"%s\")\n", comment, parsed);
+ }
+ }
+
+ int cmp(const char *s1, const char *s2) {
+ for ( ; *s1 == *s2 ; s1++,s2++ ) {
+ if ( *s1 == '\0' )
+ break;
+ }
+
+ return (*s1 - *s2);
+ }
+
+ int main() {
+ struct tm tm;
+ char s[1000];
+ size_t size;
+
+ tm.tm_sec = 4;
+ tm.tm_min = 23;
+ tm.tm_hour = 20;
+ tm.tm_mday = 21;
+ tm.tm_mon = 1;
+ tm.tm_year = 74;
+ tm.tm_wday = 4;
+ tm.tm_yday = 51;
+ tm.tm_isdst = 0;
+
+ size = strftime(s, 1000, "", &tm);
+ test((size==0) && (*s=='\0'), "strftime test #1", s);
+
+ size = strftime(s, 1000, "%a", &tm);
+ test((size==3) && !cmp(s, "Thu"), "strftime test #2", s);
+
+ size = strftime(s, 1000, "%A", &tm);
+ test((size==8) && !cmp(s, "Thursday"), "strftime test #3", s);
+
+ size = strftime(s, 1000, "%b", &tm);
+ test((size==3) && !cmp(s, "Feb"), "strftime test #4", s);
+
+ size = strftime(s, 1000, "%B", &tm);
+ test((size==8) && !cmp(s, "February"),
+ "strftime test #5", s);
+
+ size = strftime(s, 1000, "%d", &tm);
+ test((size==2) && !cmp(s, "21"),
+ "strftime test #6", s);
+
+ size = strftime(s, 1000, "%H", &tm);
+ test((size==2) && !cmp(s, "20"),
+ "strftime test #7", s);
+
+ size = strftime(s, 1000, "%I", &tm);
+ test((size==2) && !cmp(s, "08"),
+ "strftime test #8", s);
+
+ size = strftime(s, 1000, "%j", &tm);
+ test((size==3) && !cmp(s, "052"),
+ "strftime test #9", s);
+
+ size = strftime(s, 1000, "%m", &tm);
+ test((size==2) && !cmp(s, "02"),
+ "strftime test #10", s);
+
+ size = strftime(s, 1000, "%M", &tm);
+ test((size==2) && !cmp(s, "23"),
+ "strftime test #11", s);
+
+ size = strftime(s, 1000, "%p", &tm);
+ test((size==2) && !cmp(s, "PM"),
+ "strftime test #12", s);
+
+ size = strftime(s, 1000, "%S", &tm);
+ test((size==2) && !cmp(s, "04"),
+ "strftime test #13", s);
+
+ size = strftime(s, 1000, "%U", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #14", s);
+
+ size = strftime(s, 1000, "%w", &tm);
+ test((size==1) && !cmp(s, "4"),
+ "strftime test #15", s);
+
+ size = strftime(s, 1000, "%W", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #16", s);
+
+ size = strftime(s, 1000, "%y", &tm);
+ test((size==2) && !cmp(s, "74"),
+ "strftime test #17", s);
+
+ size = strftime(s, 1000, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #18", s);
+
+ size = strftime(s, 1000, "%%", &tm);
+ test((size==1) && !cmp(s, "%"),
+ "strftime test #19", s);
+
+ size = strftime(s, 5, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #20", s);
+
+ size = strftime(s, 4, "%Y", &tm);
+ test((size==0), "strftime test #21", s);
+
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #22", s);
+
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #23", s);
+
+ // 1/1/1973 was a Sunday and is in CW 1
+ tm.tm_year = 73;
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #24", s);
+
+ // 1/1/1978 was a Monday and is in CW 1
+ tm.tm_year = 78;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #25", s);
+
+ // 2/1/1999
+ tm.tm_year = 99;
+ tm.tm_yday = 1;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (53)"), "strftime test #26", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #27", s);
+
+ // 30/12/1997
+ tm.tm_year = 97;
+ tm.tm_yday = 363;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (01)"), "strftime test #28", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #29", s);
+ }
+ '''
+ self.do_run(src, '11111111111111111111111111111')
+
def test_intentional_fault(self):
# Some programs intentionally segfault themselves, we should compile that into a throw
src = r'''
@@ -6805,11 +6999,12 @@ Pass: 0.000012 0.000012''')
def test_sscanf_6(self):
src = r'''
#include <stdio.h>
-
+ #include <string.h>
int main()
{
char *date = "18.07.2013w";
char c[10];
+ memset(c, 0, 10);
int y, m, d, i;
i = sscanf(date, "%d.%d.%4d%c", &d, &m, &y, c);
printf("date: %s; day %2d, month %2d, year %4d, extra: %c, %d\n", date, d, m, y, c[0], i);
@@ -6889,7 +7084,7 @@ def process(filename):
other.close()
src = open(path_from_root('tests', 'files.cpp'), 'r').read()
- self.do_run(src, 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\ntexte\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\n',
+ self.do_run(src, 'size: 7\ndata: 100,-56,50,25,10,77,123\nloop: 100 -56 50 25 10 77 123 \ninput:hi there!\ntexto\n$\n5 : 10,30,20,11,88\nother=some data.\nseeked=me da.\nseeked=ata.\nseeked=ta.\nfscanfed: 10 - hello\nok.\ntexte\n',
post_build=post, extra_emscripten_args=['-H', 'libc/fcntl.h'])
def test_files_m(self):
@@ -6921,7 +7116,7 @@ def process(filename):
return 0;
}
'''
- self.do_run(src, 'isatty? 0,0,1\ngot: 35\ngot: 45\ngot: 25\ngot: 15\n', post_build=post)
+ self.do_run(src, 'got: 35\ngot: 45\ngot: 25\ngot: 15\nisatty? 0,0,1\n', post_build=post)
def test_fwrite_0(self):
src = r'''
@@ -7015,23 +7210,19 @@ def process(filename):
self.do_run(src, 'success', force_c=True)
def test_stat(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- var f1 = FS.createFolder('/', 'test', true, true);
- var f2 = FS.createDataFile(f1, 'file', 'abcdef', true, true);
- var f3 = FS.createLink(f1, 'link', 'file', true, true);
- var f4 = FS.createDevice(f1, 'device', function(){}, function(){});
- f1.timestamp = f2.timestamp = f3.timestamp = f4.timestamp = new Date(1200000000000);
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
- src = open(path_from_root('tests', 'stat', 'src.c'), 'r').read()
- expected = open(path_from_root('tests', 'stat', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_stat.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_chmod(self):
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_chmod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
+
+ def test_stat_mknod(self):
+ Building.COMPILER_TEST_OPTS += ['-DUSE_OLD_FS='+str(Settings.USE_OLD_FS)]
+ src = open(path_from_root('tests', 'stat', 'test_mknod.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
def test_fcntl(self):
add_pre_run = '''
@@ -10860,40 +11051,53 @@ f.close()
def measure_funcs(filename):
i = 0
start = -1
- curr = '?'
+ curr = None
ret = {}
for line in open(filename):
i += 1
if line.startswith('function '):
start = i
curr = line
- elif line.startswith('}'):
+ elif line.startswith('}') and curr:
size = i - start
- if size > 100: ret[curr] = size
+ ret[curr] = size
+ curr = None
return ret
- for outlining_limit in [1000, 2000, 5000, 0]:
- Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2', '-g3', '-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate()
- assert os.path.exists('test.js')
- shutil.copyfile('test.js', '%d_test.js' % outlining_limit)
- for engine in JS_ENGINES:
- out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True)
- self.assertContained(expected, out)
- if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
- low = expected_ranges[outlining_limit][0]
- seen = max(measure_funcs('test.js').values())
- high = expected_ranges[outlining_limit][1]
- print outlining_limit, ' ', low, '<=', seen, '<=', high
- assert low <= seen <= high
+ for debug, outlining_limits in [
+ ([], (1000,)),
+ (['-g1'], (1000,)),
+ (['-g2'], (1000,)),
+ (['-g'], (100, 250, 500, 1000, 2000, 5000, 0))
+ ]:
+ for outlining_limit in outlining_limits:
+ print '\n', debug, outlining_limit, '\n'
+ # TODO: test without -g3, tell all sorts
+ Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2'] + debug + ['-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate()
+ assert os.path.exists('test.js')
+ shutil.copyfile('test.js', '%d_test.js' % outlining_limit)
+ for engine in JS_ENGINES:
+ out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True)
+ self.assertContained(expected, out)
+ if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out)
+ if debug == ['-g']:
+ low = expected_ranges[outlining_limit][0]
+ seen = max(measure_funcs('test.js').values())
+ high = expected_ranges[outlining_limit][1]
+ print outlining_limit, ' ', low, '<=', seen, '<=', high
+ assert low <= seen <= high
test('zlib', path_from_root('tests', 'zlib', 'example.c'),
self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
{
- 1000: (380, 390),
- 2000: (395, 410),
+ 100: (190, 210),
+ 250: (300, 330),
+ 500: (250, 310),
+ 1000: (330, 400),
+ 2000: (450, 500),
5000: (800, 1100),
- 0: (1500, 1800)
+ 0: (1500, 1800)
},
args=['-I' + path_from_root('tests', 'zlib')], suffix='c')
@@ -11651,6 +11855,8 @@ f.close()
['asm', 'outline']),
(path_from_root('tools', 'test-js-optimizer-asm-outline2.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline2-output.js')).read(),
['asm', 'outline']),
+ (path_from_root('tools', 'test-js-optimizer-asm-outline3.js'), open(path_from_root('tools', 'test-js-optimizer-asm-outline3-output.js')).read(),
+ ['asm', 'outline']),
]:
print input
output = Popen(listify(NODE_JS) + [path_from_root('tools', 'js-optimizer.js'), input] + passes, stdin=PIPE, stdout=PIPE).communicate()[0]
@@ -12811,11 +13017,13 @@ Press any key to continue.'''
def test_sdl_audio(self):
shutil.copyfile(path_from_root('tests', 'sounds', 'alarmvictory_1.ogg'), os.path.join(self.get_dir(), 'sound.ogg'))
shutil.copyfile(path_from_root('tests', 'sounds', 'alarmcreatemiltaryfoot_1.wav'), os.path.join(self.get_dir(), 'sound2.wav'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'noise.ogg'), os.path.join(self.get_dir(), 'noise.ogg'))
+ shutil.copyfile(path_from_root('tests', 'sounds', 'the_entertainer.ogg'), os.path.join(self.get_dir(), 'the_entertainer.ogg'))
open(os.path.join(self.get_dir(), 'bad.ogg'), 'w').write('I claim to be audio, but am lying')
open(os.path.join(self.get_dir(), 'sdl_audio.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'sdl_audio.c')).read()))
# use closure to check for a possible bug with closure minifying away newer Audio() attributes
- Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate()
+ Popen([PYTHON, EMCC, '-O2', '--closure', '1', '--minify', '0', os.path.join(self.get_dir(), 'sdl_audio.c'), '--preload-file', 'sound.ogg', '--preload-file', 'sound2.wav', '--embed-file', 'the_entertainer.ogg', '--preload-file', 'noise.ogg', '--preload-file', 'bad.ogg', '-o', 'page.html', '-s', 'EXPORTED_FUNCTIONS=["_main", "_play", "_play2"]']).communicate()
self.run_browser('page.html', '', '/report_result?1')
def test_sdl_audio_mix_channels(self):
@@ -13181,6 +13389,9 @@ Press any key to continue.'''
def test_glshaderinfo(self):
self.btest('glshaderinfo.cpp', '1')
+ def test_glgetattachedshaders(self):
+ self.btest('glgetattachedshaders.c', '1')
+
def test_sdlglshader(self):
self.btest('sdlglshader.c', reference='sdlglshader.png', args=['-O2', '--closure', '1'])
diff --git a/tests/sdl_audio.c b/tests/sdl_audio.c
index ae1b89e9..7373d220 100644
--- a/tests/sdl_audio.c
+++ b/tests/sdl_audio.c
@@ -1,11 +1,13 @@
#include <stdio.h>
+#include <stdlib.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <assert.h>
#include <emscripten.h>
+#include <sys/stat.h>
-Mix_Chunk *sound, *sound2;
-
+Mix_Chunk *sound, *sound2, *sound3;
+Mix_Music * music;
int play2();
int play() {
@@ -28,6 +30,9 @@ int play2() {
int channel2 = Mix_PlayChannel(-1, sound2, 0);
assert(channel2 == 1);
+ int channel3 = Mix_PlayChannel(-1, sound3, 0);
+ assert(channel3 == 2);
+ assert(Mix_PlayMusic(music, 1) == 0);
return channel2;
}
@@ -39,6 +44,26 @@ int main(int argc, char **argv) {
sound = Mix_LoadWAV("sound.ogg");
assert(sound);
+
+ {
+ struct stat info;
+ int result = stat("noise.ogg", &info);
+ char * bytes = malloc( info.st_size );
+ FILE * f = fopen( "noise.ogg", "rb" );
+ fread( bytes, 1, info.st_size, f );
+ fclose(f);
+
+ SDL_RWops * ops = SDL_RWFromConstMem(bytes, info.st_size);
+ sound3 = Mix_LoadWAV_RW(ops, 0);
+ SDL_FreeRW(ops);
+ free(bytes);
+ }
+
+ {
+ music = Mix_LoadMUS("the_entertainer.ogg");
+ }
+
+
sound2 = Mix_LoadWAV("sound2.wav");
assert(sound);
diff --git a/tests/stat/output.txt b/tests/stat/output.txt
deleted file mode 100644
index 1e6ae74e..00000000
--- a/tests/stat/output.txt
+++ /dev/null
@@ -1,202 +0,0 @@
---stat FOLDER--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 2
-st_mode: 040777
-st_nlink: 1
-st_rdev: 0
-st_size: 4096
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat FILE--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat DEVICE--
-ret: 0
-errno: 0
-st_dev: 5
-st_ino: 5
-st_mode: 020777
-st_nlink: 1
-st_rdev: 5
-st_size: 0
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 0
-S_ISBLK: 0
-S_ISCHR: 1
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---stat LINK--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---lstat LINK--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 4
-st_mode: 0120777
-st_nlink: 1
-st_rdev: 0
-st_size: 4
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 1
-S_ISSOCK: 0
-
---fstat FILE--
-ret: 0
-errno: 0
-st_dev: 1
-st_ino: 3
-st_mode: 0100777
-st_nlink: 1
-st_rdev: 0
-st_size: 6
-st_atime: 1200000000
-st_mtime: 1200000000
-st_ctime: 1200000000
-st_blksize: 4096
-st_blocks: 1
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---chmod FILE--
-ret: 0
-errno: 0
-st_mode: 0100222
-st_mtime changed: 1
-
---fchmod FILE--
-ret: 0
-errno: 0
-st_mode: 0100777
-st_mtime changed: 1
-
---chmod FOLDER--
-ret: 0
-errno: 0
-st_mode: 040555
-st_mtime changed: 1
-
---chmod LINK--
-ret: 0
-errno: 0
-st_mode: 0100000
-
---mkdir--
-ret: 0
-errno: 0
-st_mode: 040777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FILE--
-ret: 0
-errno: 0
-st_mode: 0100777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 0
-S_ISFIFO: 0
-S_ISREG: 1
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FOLDER--
-ret: 0
-errno: 0
-st_mode: 040777
-S_ISBLK: 0
-S_ISCHR: 0
-S_ISDIR: 1
-S_ISFIFO: 0
-S_ISREG: 0
-S_ISLNK: 0
-S_ISSOCK: 0
-
---mknod FIFO--
-ret: -1
-errno: 22
-
---mknod DEVICE--
-ret: -1
-errno: 22
-
---mkfifo--
-ret: -1
-errno: 30
diff --git a/tests/stat/src.c b/tests/stat/src.c
deleted file mode 100644
index dc5a0198..00000000
--- a/tests/stat/src.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
-Note: Hardcoded st_ino values etc. may change with minor changes to the library impl.
- In such an event, we will need to update output.txt here.
-*/
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-int main() {
- struct stat s;
-
- printf("--stat FOLDER--\n");
- printf("ret: %d\n", stat("/test", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat FILE--\n");
- printf("ret: %d\n", stat("/test/file", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat DEVICE--\n");
- printf("ret: %d\n", stat("/test/device", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--stat LINK--\n");
- printf("ret: %d\n", stat("/test/link", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--lstat LINK--\n");
- printf("ret: %d\n", lstat("/test/link", &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--fstat FILE--\n");
- printf("ret: %d\n", fstat(open("/test/file", O_RDONLY, 0777), &s));
- printf("errno: %d\n", errno);
- printf("st_dev: %lu\n", s.st_dev);
- printf("st_ino: %lu\n", s.st_ino);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_nlink: %d\n", s.st_nlink);
- printf("st_rdev: %lu\n", s.st_rdev);
- printf("st_size: %ld\n", s.st_size);
- printf("st_atime: %ld\n", s.st_atime);
- printf("st_mtime: %ld\n", s.st_mtime);
- printf("st_ctime: %ld\n", s.st_ctime);
- printf("st_blksize: %ld\n", s.st_blksize);
- printf("st_blocks: %ld\n", s.st_blocks);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod FILE--\n");
- printf("ret: %d\n", chmod("/test/file", 0200));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--fchmod FILE--\n");
- printf("ret: %d\n", fchmod(open("/test/file", O_WRONLY, 0777), 0777));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod FOLDER--\n");
- printf("ret: %d\n", chmod("/test", 0400));
- printf("errno: %d\n", errno);
- stat("/test", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("st_mtime changed: %d\n", s.st_mtime != 1200000000l);
- memset(&s, 0, sizeof s);
-
- printf("\n--chmod LINK--\n");
- printf("ret: %d\n", chmod("/test/link", 0000));
- printf("errno: %d\n", errno);
- stat("/test/file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- memset(&s, 0, sizeof s);
-
- // Make sure we can create stuff in the root.
- chmod("/", 0777);
-
- printf("\n--mkdir--\n");
- printf("ret: %d\n", mkdir("/test-mkdir", 0777));
- printf("errno: %d\n", errno);
- stat("/test-mkdir", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FILE--\n");
- printf("ret: %d\n", mknod("/test-mknod-file", S_IFREG | 0777, 0));
- printf("errno: %d\n", errno);
- stat("/test-mknod-file", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FOLDER--\n");
- printf("ret: %d\n", mknod("/test-mknod-dir", S_IFDIR | 0777, 0));
- printf("errno: %d\n", errno);
- stat("/test-mknod-dir", &s);
- printf("st_mode: 0%o\n", s.st_mode);
- printf("S_ISBLK: %d\n", S_ISBLK(s.st_mode));
- printf("S_ISCHR: %d\n", S_ISCHR(s.st_mode));
- printf("S_ISDIR: %d\n", S_ISDIR(s.st_mode));
- printf("S_ISFIFO: %d\n", S_ISFIFO(s.st_mode));
- printf("S_ISREG: %d\n", S_ISREG(s.st_mode));
- printf("S_ISLNK: %d\n", S_ISLNK(s.st_mode));
- printf("S_ISSOCK: %d\n", S_ISSOCK(s.st_mode));
- memset(&s, 0, sizeof s);
-
- printf("\n--mknod FIFO--\n");
- printf("ret: %d\n", mknod("/test-mknod-fifo", S_IFIFO | 0777, 0));
- printf("errno: %d\n", errno);
-
- printf("\n--mknod DEVICE--\n");
- printf("ret: %d\n", mknod("/test-mknod-device", S_IFCHR | 0777, 123));
- printf("errno: %d\n", errno);
-
- printf("\n--mkfifo--\n");
- printf("ret: %d\n", mkfifo("/test-mkfifo", 0777));
- printf("errno: %d\n", errno);
-
- return 0;
-}
diff --git a/tests/stat/test_chmod.c b/tests/stat/test_chmod.c
new file mode 100644
index 00000000..94e6c12b
--- /dev/null
+++ b/tests/stat/test_chmod.c
@@ -0,0 +1,153 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void create_file(const char *path, const char *buffer, int mode) {
+ int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ assert(fd >= 0);
+
+ int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+ assert(err == (sizeof(char) * strlen(buffer)));
+
+ close(fd);
+}
+
+void setup() {
+ create_file("file", "abcdef", 0777);
+ symlink("file", "file-link");
+ // some platforms use 777, some use 755 by default for symlinks
+ // make sure we're using 777 for the test
+ lchmod("file-link", 0777);
+ mkdir("folder", 0777);
+}
+
+void cleanup() {
+ unlink("file-link");
+ unlink("file");
+ rmdir("folder");
+}
+
+void test() {
+ int err;
+ int lastctime;
+ struct stat s;
+
+ //
+ // chmod a file
+ //
+ // get the current ctime for the file
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ // do the actual chmod
+ err = chmod("file", 0200);
+ assert(!err);
+
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0222 | S_IFREG));
+#else
+ assert(s.st_mode == (0200 | S_IFREG));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // fchmod a file
+ //
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ err = fchmod(open("file", O_WRONLY), 0100);
+ assert(!err);
+
+ memset(&s, 0, sizeof s);
+ stat("file", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0000 | S_IFREG));
+#else
+ assert(s.st_mode == (0100 | S_IFREG));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // chmod a folder
+ //
+ // get the current ctime for the folder
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+ lastctime = s.st_ctime;
+ sleep(1);
+
+ // do the actual chmod
+ err = chmod("folder", 0300);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0222 | S_IFDIR));
+#else
+ assert(s.st_mode == (0300 | S_IFDIR));
+#endif
+ assert(s.st_ctime != lastctime);
+
+ //
+ // chmod a symlink's target
+ //
+ err = chmod("file-link", 0400);
+ assert(!err);
+
+ // make sure the file it references changed
+ stat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFREG));
+#else
+ assert(s.st_mode == (0400 | S_IFREG));
+#endif
+
+ // but the link didn't
+ lstat("file-link", &s);
+ assert(s.st_mode == (0777 | S_IFLNK));
+
+ //
+ // chmod the actual symlink
+ //
+ err = lchmod("file-link", 0500);
+ assert(!err);
+
+ // make sure the file it references didn't change
+ stat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFREG));
+#else
+ assert(s.st_mode == (0400 | S_IFREG));
+#endif
+
+ // but the link did
+ lstat("file-link", &s);
+#if USE_OLD_FS
+ assert(s.st_mode == (0555 | S_IFLNK));
+#else
+ assert(s.st_mode == (0500 | S_IFLNK));
+#endif
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/stat/test_mknod.c b/tests/stat/test_mknod.c
new file mode 100644
index 00000000..4cff57d9
--- /dev/null
+++ b/tests/stat/test_mknod.c
@@ -0,0 +1,96 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void setup() {
+ mkdir("folder-readonly", 0555);
+}
+
+void cleanup() {
+ unlink("mknod-file");
+ unlink("mknod-device");
+ rmdir("folder");
+ rmdir("folder-readonly");
+}
+
+void test() {
+ int err;
+ struct stat s;
+
+ //
+ // mknod
+ // mknod is _extremely_ unportable for anything other
+ // than a FIFO. so, the tests are disabled when running
+ // natively as they'd be utterly inconsistent.
+ //
+#if EMSCRIPTEN
+
+ // mknod a folder
+ err = mknod("mknod-folder", S_IFDIR | 0777, 0);
+ assert(err);
+ assert(errno == EINVAL);
+
+ // mknod fifo
+ err = mknod("mknod-fifo", S_IFIFO | 0777, 0);
+ assert(err);
+ assert(errno == EPERM);
+
+ // mknod a file
+ err = mknod("mknod-file", S_IFREG | 0777, 0);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("mknod-file", &s);
+ assert(S_ISREG(s.st_mode));
+
+ // mknod a character device
+ err = mknod("mknod-device", S_IFCHR | 0777, 123);
+#if USE_OLD_FS
+ assert(err);
+ assert(errno == EPERM);
+#else
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("mknod-device", &s);
+ assert(S_ISCHR(s.st_mode));
+#endif
+
+#endif
+
+ //
+ // mkdir
+ //
+ // can't mkdir in a readonly dir
+ err = mkdir("folder-readonly/subfolder", 0777);
+ assert(err);
+ assert(errno == EACCES);
+
+ // regular creation
+ err = mkdir("folder", 0777);
+ assert(!err);
+ memset(&s, 0, sizeof s);
+ stat("folder", &s);
+ assert(S_ISDIR(s.st_mode));
+
+ // try to re-create the same folder
+ err = mkdir("folder", 0777);
+ assert(err);
+ assert(errno == EEXIST);
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/stat/test_stat.c b/tests/stat/test_stat.c
new file mode 100644
index 00000000..14e88370
--- /dev/null
+++ b/tests/stat/test_stat.c
@@ -0,0 +1,167 @@
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+void create_file(const char *path, const char *buffer, int mode) {
+ int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ assert(fd >= 0);
+
+ int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+ assert(err == (sizeof(char) * strlen(buffer)));
+
+ close(fd);
+}
+
+void setup() {
+ struct utimbuf t = {1200000000, 1200000000};
+
+ mkdir("folder", 0777);
+ create_file("folder/file", "abcdef", 0777);
+ symlink("file", "folder/file-link");
+
+ utime("folder/file", &t);
+ utime("folder", &t);
+}
+
+void cleanup() {
+ unlink("folder/file");
+ unlink("folder/file-link");
+ rmdir("folder");
+}
+
+void test() {
+ int err;
+ struct stat s;
+
+ // stat a folder
+ memset(&s, 0, sizeof(s));
+ err = stat("folder", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISDIR(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#ifdef EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // stat a file
+ memset(&s, 0, sizeof(s));
+ err = stat("folder/file", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // fstat a file (should match file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = fstat(open("folder/file", O_RDONLY), &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // stat a device
+ memset(&s, 0, sizeof(s));
+ err = stat("/dev/null", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISCHR(s.st_mode));
+ assert(s.st_nlink);
+#if !USE_OLD_FS
+ // old FS doesn't store proper device ids
+#ifndef __APPLE__
+ // mac uses makedev(3, 2) for /dev/null
+ assert(s.st_rdev == makedev(1, 3));
+#endif
+#endif
+ assert(!s.st_size);
+ assert(s.st_atime);
+ assert(s.st_mtime);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 0);
+#endif
+
+ // stat a link (should match the file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = stat("folder/file-link", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISREG(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 6);
+ assert(s.st_atime == 1200000000);
+ assert(s.st_mtime == 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ // lstat a link (should NOT match the file stat from above)
+ memset(&s, 0, sizeof(s));
+ err = lstat("folder/file-link", &s);
+ assert(!err);
+ assert(s.st_dev);
+ assert(s.st_ino);
+ assert(S_ISLNK(s.st_mode));
+ assert(s.st_nlink);
+ assert(s.st_rdev == 0);
+ assert(s.st_size == 4); // strlen("file")
+ assert(s.st_atime != 1200000000); // should NOT match the utime call we did for dir/file
+ assert(s.st_mtime != 1200000000);
+ assert(s.st_ctime);
+#if EMSCRIPTEN
+ assert(s.st_blksize == 4096);
+ assert(s.st_blocks == 1);
+#endif
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py
index 31825544..6fdec3a9 100644
--- a/tools/find_bigfuncs.py
+++ b/tools/find_bigfuncs.py
@@ -7,16 +7,17 @@ import os, sys, re
filename = sys.argv[1]
i = 0
start = -1
-curr = '?'
+curr = None
data = []
for line in open(filename):
i += 1
if line.startswith('function '):
start = i
curr = line
- elif line.startswith('}'):
+ elif line.startswith('}') and curr:
size = i - start
- data.append([curr, size]);
+ data.append([curr, size])
+ curr = None
data.sort(lambda x, y: x[1] - y[1])
print ''.join(['%6d : %s' % (x[1], x[0]) for x in data])
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 46b9c731..95d9b82f 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1743,7 +1743,7 @@ function registerize(ast) {
}
});
vacuum(fun);
- if (extraInfo) {
+ if (extraInfo && extraInfo.globals) {
assert(asm);
var usedGlobals = {};
var nextLocal = 0;
@@ -1784,16 +1784,17 @@ function registerize(ast) {
}
}
});
- assert(fun[1] in extraInfo.globals, fun[1]);
- fun[1] = extraInfo.globals[fun[1]];
- assert(fun[1]);
+ if (fun[1] in extraInfo.globals) { // if fun was created by a previous optimization pass, it will not be here
+ fun[1] = extraInfo.globals[fun[1]];
+ assert(fun[1]);
+ }
var nextRegName = 0;
}
var regTypes = {};
function getNewRegName(num, name) {
if (!asm) return 'r' + num;
var type = asmData.vars[name];
- if (!extraInfo) {
+ if (!extraInfo || !extraInfo.globals) {
var ret = (type ? 'd' : 'i') + num;
regTypes[ret] = type;
return ret;
@@ -2872,6 +2873,7 @@ function outline(ast) {
defs[name] = node;
} else {
if (name in asmData.params) {
+ assignments[name] = (assignments[name] || 1) + 1; // init to 1 for initial parameter assignment
considered[name] = true; // this parameter is not ssa, it must be in a hand-optimized function, so it is not trivial
}
}
@@ -2997,6 +2999,63 @@ function outline(ast) {
});
}
+ // Try to flatten out code as much as possible, to make outlining more feasible.
+ function flatten(func, asmData) {
+ var minSize = sizeToOutline/3;
+ var helperId = 0;
+ function getHelper() {
+ while (1) {
+ var ret = 'helper$' + (helperId++);
+ if (!(ret in asmData.vars) && !(ret in asmData.params)) {
+ asmData.vars[ret] = ASM_INT;
+ return ret;
+ }
+ }
+ }
+ traverse(func, function(node) {
+ var stats = getStatements(node);
+ if (stats) {
+ for (var i = 0; i < stats.length; i++) {
+ var node = stats[i]; // step over param
+ var type = node[0];
+ if (measureSize(node) >= minSize) {
+ if (type === 'if' && node[3]) {
+ var reps = [];
+ var helper = getHelper();
+ // clear helper
+ reps.push(['stat', ['assign', true, ['name', helper], ['num', 1]]]);
+ // gather parts
+ var parts = [];
+ var curr = node;
+ while (1) {
+ parts.push({ condition: curr[1], body: curr[2] });
+ curr = curr[3];
+ if (!curr) break;
+ if (curr[0] != 'if') {
+ parts.push({ condition: null, body: curr });
+ break;
+ }
+ }
+ // generate flattened code
+ parts.forEach(function(part) {
+ var condition = ['name', helper];
+ if (part.condition) condition = ['conditional', condition, part.condition, ['num', 0]];
+ assert(part.body[0] == 'block');
+ reps.push(makeIf(condition, part.body[1]));
+ getStatements(part.body).unshift(['stat', ['assign', true, ['name', helper], ['num', 0]]]);
+ });
+ // replace code and update i
+ stats.splice.apply(stats, [i, 1].concat(reps));
+ i--; // negate loop increment
+ i += reps.length;
+ continue;
+ }
+ }
+ }
+ }
+ });
+ }
+
// Prepares information for spilling of local variables
function analyzeFunction(func, asmData) {
var stack = []; // list of variables, each gets 8 bytes
@@ -3008,15 +3067,17 @@ function outline(ast) {
}
asmData.stackPos = {};
var stackSize = getStackBumpSize(func);
+ if (stackSize % 8 === 0) stackSize += 8 - (stackSize % 8);
for (var i = 0; i < stack.length; i++) {
asmData.stackPos[stack[i]] = stackSize + i*8;
}
- // Reserve an extra two spots: one for control flow var, the other for control flow data
+ // Reserve an extra two spots per possible outlining: one for control flow var, the other for control flow data
// The control variables are zeroed out when calling an outlined function, and after using
// the value after they return.
- asmData.extraStackSize = (stack.length + 2)*8;
- asmData.controlStackPos = stackSize + asmData.extraStackSize - 16;
- asmData.controlDataStackPos = stackSize + asmData.extraStackSize - 8;
+ asmData.maxOutlinings = Math.round(3*measureSize(func)/sizeToOutline);
+ asmData.totalStackSize = stackSize + (stack.length + 2*asmData.maxOutlinings)*8;
+ asmData.controlStackPos = function(i) { return stackSize + (stack.length + i)*8 };
+ asmData.controlDataStackPos = function(i) { return stackSize + (stack.length + i)*8 + 4 };
asmData.splitCounter = 0;
}
@@ -3120,13 +3181,15 @@ function outline(ast) {
var sizeToOutline = extraInfo.sizeToOutline;
var level = 0;
- var costs = {}; // new function name => overhead cost of outlining
+ var outliningParents = {}; // function name => parent it was outlined from
function doOutline(func, asmData, stats, start, end) {
+ if (asmData.splitCounter === asmData.maxOutlinings) return [];
if (!extraInfo.allowCostlyOutlines) var originalStats = copy(stats);
var code = stats.slice(start, end+1);
var funcSize = measureSize(func);
- var newIdent = func[1] + '$' + (asmData.splitCounter++);
+ var outlineIndex = asmData.splitCounter++;
+ var newIdent = func[1] + '$' + outlineIndex;
// analyze variables, and find 'owned' variables - that only appear in the outlined code, and do not need any spill support
var codeInfo = analyzeCode(func, asmData, code);
var allCodeInfo = analyzeCode(func, asmData, func);
@@ -3139,15 +3202,15 @@ function outline(ast) {
});
var reps = [];
// wipe out control variable
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', 0])]);
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', 0])]); // XXX not really needed
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
// add spills and reads before and after the call to the outlined code, and in the outlined code itself
keys(setUnion(codeInfo.reads, codeInfo.writes)).forEach(function(v) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
});
- reps.push(['stat', ['assign', true, ['name', 'sp'], makeAsmCoercion(['call', ['name', newIdent], [['name', 'sp']]], ASM_INT)]]);
+ reps.push(['stat', ['call', ['name', newIdent], [['name', 'sp']]]]);
for (var v in codeInfo.writes) {
if (!(v in owned)) {
reps.push(['stat', ['assign', true, ['name', v], makeAsmCoercion(['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], getAsmType(v, asmData))]]);
@@ -3176,11 +3239,11 @@ function outline(ast) {
if (type == 'return') {
ret = [];
if (!node[1]) {
- ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', CONTROL_RETURN_VOID])]);
+ ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', CONTROL_RETURN_VOID])]);
} else {
var type = detectAsmCoercion(node[1], asmData);
- ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', type == ASM_INT ? CONTROL_RETURN_INT : CONTROL_RETURN_DOUBLE])]);
- ret.push(['stat', makeAssign(makeStackAccess(type, asmData.controlDataStackPos), node[1])]);
+ ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', type == ASM_INT ? CONTROL_RETURN_INT : CONTROL_RETURN_DOUBLE])]);
+ ret.push(['stat', makeAssign(makeStackAccess(type, asmData.controlDataStackPos(outlineIndex)), node[1])]);
}
ret.push(['stat', ['break', 'OL']]);
} else if (type == 'break') {
@@ -3188,20 +3251,20 @@ function outline(ast) {
if (label == 'OL') continue; // this was just added before us, it is new replacement code
if (!label && breakCapturers > 0) continue; // no label, and captured
if (label && (label in codeInfo.labels)) continue; // label, and defined in this code, so captured
- ret = [['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', label ? CONTROL_BREAK_LABEL : CONTROL_BREAK])]];
+ ret = [['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', label ? CONTROL_BREAK_LABEL : CONTROL_BREAK])]];
if (label) {
assert(label in codeInfo.breaks);
- ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', codeInfo.breaks[label]])]);
+ ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', codeInfo.breaks[label]])]);
}
ret.push(['stat', ['break', 'OL']]);
} else if (type == 'continue') {
var label = node[1] || 0;
if (!label && continueCapturers > 0) continue; // no label, and captured
if (label && (label in codeInfo.labels)) continue; // label, and defined in this code, so captured
- ret = [['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', label ? CONTROL_CONTINUE_LABEL : CONTROL_CONTINUE])]];
+ ret = [['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', label ? CONTROL_CONTINUE_LABEL : CONTROL_CONTINUE])]];
if (label) {
assert(label in codeInfo.continues);
- ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', codeInfo.continues[label]])]);
+ ret.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', codeInfo.continues[label]])]);
}
ret.push(['stat', ['break', 'OL']]);
}
@@ -3223,18 +3286,18 @@ function outline(ast) {
// read the control data at the callsite to the outlined function, and clear the control values
reps.push(['stat', makeAssign(
['name', 'tempValue'],
- makeAsmCoercion(makeStackAccess(ASM_INT, asmData.controlStackPos), ASM_INT)
+ makeAsmCoercion(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ASM_INT)
)]);
reps.push(['stat', makeAssign(
['name', 'tempInt'],
- makeAsmCoercion(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ASM_INT)
+ makeAsmCoercion(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ASM_INT)
)]);
reps.push(['stat', makeAssign(
['name', 'tempDouble'],
- makeAsmCoercion(makeStackAccess(ASM_DOUBLE, asmData.controlDataStackPos), ASM_DOUBLE)
+ makeAsmCoercion(makeStackAccess(ASM_DOUBLE, asmData.controlDataStackPos(outlineIndex)), ASM_DOUBLE)
)]);
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos), ['num', 0])]);
- reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos), ['num', 0])]); // XXX not really needed
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlStackPos(outlineIndex)), ['num', 0])]);
+ reps.push(['stat', makeAssign(makeStackAccess(ASM_INT, asmData.controlDataStackPos(outlineIndex)), ['num', 0])]); // XXX not really needed
// use the control data information
if (codeInfo.hasReturn) {
reps.push(makeIf(
@@ -3296,8 +3359,6 @@ function outline(ast) {
code.push(['stat', ['assign', true, ['sub', ['name', getAsmType(v, asmData) == ASM_INT ? 'HEAP32' : 'HEAPF32'], ['binary', '>>', ['binary', '+', ['name', 'sp'], ['num', asmData.stackPos[v]]], ['num', '2']]], ['name', v]]]);
}
}
- // add final return of sp. the model is that we send sp as the single param, and get it back out
- code.push(['stat', ['return', makeAsmCoercion(['name', 'sp'], ASM_INT)]]);
// finalize
var newFunc = ['defun', newIdent, ['sp'], code];
var newAsmData = { params: { sp: ASM_INT }, vars: {} };
@@ -3305,11 +3366,16 @@ function outline(ast) {
if (v != 'sp') newAsmData.vars[v] = getAsmType(v, asmData);
}
for (var v in codeInfo.writes) {
- if (v != 'sp') newAsmData.vars[v] = getAsmType(v, asmData);
+ assert(v != 'sp'); // we send sp as a read-only parameter, cannot be written to in outlined code
+ newAsmData.vars[v] = getAsmType(v, asmData);
}
denormalizeAsm(newFunc, newAsmData);
+ // add outline call markers (we cannot do later outlinings that cut through an outlining call)
+ reps.unshift(['begin-outline-call', newIdent]);
+ reps.push(['end-outline-call', newIdent]);
// replace in stats
stats.splice.apply(stats, [start, end-start+1].concat(reps));
+ // final evaluation and processing
if (!extraInfo.allowCostlyOutlines && (measureSize(func) >= funcSize || measureSize(newFunc) >= funcSize)) {
// abort, this was pointless
stats.length = originalStats.length;
@@ -3327,33 +3393,41 @@ function outline(ast) {
getStatements(func).push(['stat', ['return', makeAsmCoercion(['num', 0], allCodeInfo.hasReturnInt ? ASM_INT : ASM_DOUBLE)]]);
}
}
- // the cost is the total size increase of all code, after the outlining operation. We also
- // inherit the outlining cost of the parent function, if any, so the repeated outlining
- // cannot infinitely recurse.
- costs[newIdent] = measureSize(func) + measureSize(newFunc) - funcSize + (costs[func[1]] || 0);
+ outliningParents[newIdent] = func[1];
return [newFunc];
}
function outlineStatements(func, asmData, stats, maxSize) {
level++;
- printErr('outlineStatements: ' + [func[1], level, measureSize(func)]);
+ //printErr('outlineStatements: ' + [func[1], level, measureSize(func)]);
var lastSize = measureSize(stats);
if (lastSize < sizeToOutline) { level--; return }
var ret = [];
var sizeSeen = 0;
var end = stats.length-1;
var i = stats.length;
- var minIndex = stats == getStatements(func) ? getFirstIndexInNormalized(func, asmData) : 0;
var canRestart = false;
+ var minIndex = 0;
+ function calcMinIndex() {
+ if (stats == getStatements(func)) {
+ minIndex = getFirstIndexInNormalized(func, asmData);
+ for (var i = minIndex; i < stats.length; i++) {
+ var stat = stats[i];
+ if (stat[0] == 'stat') stat = stat[1];
+ if (stat[0] == 'assign' && stat[2][0] == 'name' && stat[2][1] == 'sp') minIndex = i+1; // cannot outline |sp = |
+ }
+ }
+ }
while (1) {
i--;
+ calcMinIndex();
if (i < minIndex) {
// we might be done. but, if we have just outlined, do a further attempt from the beginning.
// (but only if the total costs are not extravagant)
var currSize = measureSize(stats);
var outlinedSize = measureSize(ret);
if (canRestart && currSize > 1.2*sizeToOutline && lastSize - currSize >= 0.75*sizeToOutline) {
- printErr('restarting ' + func[1] + ' since ' + [currSize, outlinedSize, lastSize] + ' in level ' + level);
+ //printErr('restarting ' + func[1] + ' since ' + [currSize, outlinedSize, lastSize] + ' in level ' + level);
lastSize = currSize;
i = stats.length;
end = stats.length-1;
@@ -3364,7 +3438,17 @@ function outline(ast) {
break;
}
}
+
var stat = stats[i];
+ while (stat[0] === 'end-outline-call') {
+ // we cannot outline through an outline call, so include all of it
+ while (stats[--i][0] !== 'begin-outline-call') {
+ assert(i >= minIndex+1);
+ assert(stats[i][0] !== 'end-outline-call');
+ }
+ stat = stats[i];
+ }
+
var size = measureSize(stat);
//printErr(level + ' size ' + [i, size]);
if (size >= sizeToOutline) {
@@ -3382,7 +3466,7 @@ function outline(ast) {
});
if (ret.length > pre) {
// we outlined recursively, reset our state here
- printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level);
+ //printErr('successful outline in recursion ' + func[1] + ' due to recursive in level ' + level);
end = i-1;
sizeSeen = 0;
canRestart = true;
@@ -3390,10 +3474,10 @@ function outline(ast) {
}
}
sizeSeen += size;
- // If this is big enough to outline, but no too big (if very close to the size of the full function,
+ // If this is big enough to outline, but not too big (if very close to the size of the full function,
// outlining is pointless; remove stats from the end to try to achieve the good case), then outline.
// Also, try to reduce the size if it is much larger than the hoped-for size
- while ((sizeSeen > maxSize || sizeSeen > 2*sizeToOutline) && i < end) {
+ while ((sizeSeen > maxSize || sizeSeen > 2*sizeToOutline) && end > i+1 && stats[end][0] !== 'begin-outline-call' && stats[end][0] !== 'end-outline-call') {
sizeSeen -= measureSize(stats[end]);
if (sizeSeen >= sizeToOutline) {
end--;
@@ -3402,9 +3486,26 @@ function outline(ast) {
break;
}
}
+ // verify we are not outlining through an outline call
+ var sum = 0;
+ stats.slice(i, end+1).forEach(function(stat) {
+ if (stat[0] == 'begin-outline-call') {
+ assert(sum == 0);
+ sum++;
+ } else if (stat[0] == 'end-outline-call') {
+ assert(sum == 1);
+ sum--;
+ }
+ });
+ assert(sum == 0);
+ // final decision and action
if (sizeSeen >= sizeToOutline && sizeSeen <= maxSize) {
- ret.push.apply(ret, doOutline(func, asmData, stats, i, end)); // outline [i, .. ,end] inclusive
- printErr('performed outline on ' + func[1] + ' of ' + sizeSeen + ', func is now size ' + measureSize(func));
+ assert(i >= minIndex);
+ var newFuncs = doOutline(func, asmData, stats, i, end); // outline [i, .. ,end] inclusive
+ if (newFuncs.length) {
+ ret.push.apply(ret, newFuncs);
+ printErr('performed outline on ' + func[1] + ' of ' + sizeSeen + ', func is now size ' + measureSize(func));
+ }
sizeSeen = 0;
end = i-1;
canRestart = true;
@@ -3436,6 +3537,7 @@ function outline(ast) {
if (size >= sizeToOutline) {
printErr('trying to reduce the size of ' + func[1] + ' which is ' + size + ' (>= ' + sizeToOutline + ')');
aggressiveVariableElimination(func, asmData);
+ flatten(func, asmData);
analyzeFunction(func, asmData);
var stats = getStatements(func);
var ret = outlineStatements(func, asmData, stats, 0.9*size);
@@ -3443,17 +3545,16 @@ function outline(ast) {
if (ret && ret.length > 0) {
newFuncs.push.apply(newFuncs, ret);
// We have outlined. Add stack support
- var extraSpace = asmData.extraStackSize;
if ('sp' in asmData.vars) {
// find stack bump (STACKTOP = STACKTOP + X | 0) and add the extra space
var stackBumpNode = getStackBumpNode(stats);
- if (stackBumpNode) stackBumpNode[3][2][3][1] += extraSpace;
+ if (stackBumpNode) stackBumpNode[3][2][3][1] = asmData.totalStackSize;
} else if (!('sp' in asmData.params)) { // if sp is a param, then we are an outlined function, no need to add stack support for us
// add sp variable and stack bump
var index = getFirstIndexInNormalized(func, asmData);
stats.splice(index, 0,
['stat', makeAssign(['name', 'sp'], ['name', 'STACKTOP'])],
- ['stat', makeAssign(['name', 'STACKTOP'], ['binary', '|', ['binary', '+', ['name', 'STACKTOP'], ['num', extraSpace]], ['num', 0]])]
+ ['stat', makeAssign(['name', 'STACKTOP'], ['binary', '|', ['binary', '+', ['name', 'STACKTOP'], ['num', asmData.totalStackSize]], ['num', 0]])]
);
asmData.vars.sp = ASM_INT; // no need to add to vars, we are about to denormalize anyhow
// we added sp, so we must add stack popping
@@ -3502,6 +3603,11 @@ function outline(ast) {
//more = funcs.length > 0;
}
}
+
+ // clear out markers
+ traverse(ast, function(node, type) {
+ if (type === 'begin-outline-call' || type === 'end-outline-call') return emptyNode();
+ });
}
// Last pass utilities
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index 4e7d5474..acb87460 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -74,7 +74,7 @@ class Minifier:
f = open(temp_file, 'w')
f.write(shell)
f.write('\n')
- f.write('// EXTRA_INFO:' + self.serialize())
+ f.write('// EXTRA_INFO:' + json.dumps(self.serialize()))
f.close()
output = subprocess.Popen(self.js_engine +
@@ -91,10 +91,10 @@ class Minifier:
def serialize(self):
- return json.dumps({
+ return {
'names': self.names,
'globals': self.globs
- })
+ }
start_funcs_marker = '// EMSCRIPTEN_START_FUNCS\n'
end_funcs_marker = '// EMSCRIPTEN_END_FUNCS\n'
@@ -256,9 +256,12 @@ EMSCRIPTEN_FUNCS();
f.write(chunk)
f.write(suffix_marker)
if minify_globals:
- assert not extra_info
+ if extra_info:
+ for key, value in extra_info.iteritems():
+ assert key not in minify_info or value == minify_info[key], [key, value, minify_info[key]]
+ minify_info[key] = value
f.write('\n')
- f.write('// EXTRA_INFO:' + minify_info)
+ f.write('// EXTRA_INFO:' + json.dumps(minify_info))
elif extra_info:
f.write('\n')
f.write('// EXTRA_INFO:' + json.dumps(extra_info))
diff --git a/tools/test-js-optimizer-asm-outline1-output.js b/tools/test-js-optimizer-asm-outline1-output.js
index 6ef32f54..65fbd6a5 100644
--- a/tools/test-js-optimizer-asm-outline1-output.js
+++ b/tools/test-js-optimizer-asm-outline1-output.js
@@ -1,58 +1,58 @@
function lin() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 136 | 0;
c(1);
c(2);
c(3);
c(4);
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = lin$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ lin$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = lin$0(sp) | 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ lin$0(sp);
STACKTOP = sp;
}
function lin2() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 136 | 0;
while (1) {
c(1);
c(2);
c(3);
c(4);
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ lin2$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = lin2$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = lin2$0(sp) | 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ lin2$0(sp);
}
STACKTOP = sp;
}
function lin3() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 152 | 0;
while (1) {
c(1);
c(2);
c(3);
c(4);
c(5);
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = lin3$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ lin3$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = lin3$0(sp) | 0;
- tempValue = HEAP32[sp + 0 >> 2] | 0;
- tempInt = HEAP32[sp + 8 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 8 >> 2];
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ lin3$0(sp);
+ tempValue = HEAP32[sp + 8 >> 2] | 0;
+ tempInt = HEAP32[sp + 12 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 12 >> 2];
HEAP32[sp + 8 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
if ((tempValue | 0) == 6) {
STACKTOP = sp;
return tempInt | 0;
@@ -64,23 +64,23 @@ function lin3() {
function lin4() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 152 | 0;
while (1) {
c(1);
c(2);
c(3);
c(4);
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ lin4$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = lin4$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = lin4$0(sp) | 0;
- tempValue = HEAP32[sp + 0 >> 2] | 0;
- tempInt = HEAP32[sp + 8 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 8 >> 2];
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ lin4$0(sp);
+ tempValue = HEAP32[sp + 8 >> 2] | 0;
+ tempInt = HEAP32[sp + 12 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 12 >> 2];
HEAP32[sp + 8 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
if ((tempValue | 0) == 1) {
break;
}
@@ -91,23 +91,23 @@ function lin4() {
function lin5() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 152 | 0;
while (1) {
c(1);
c(2);
c(3);
c(4);
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = lin5$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ lin5$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = lin5$0(sp) | 0;
- tempValue = HEAP32[sp + 0 >> 2] | 0;
- tempInt = HEAP32[sp + 8 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 8 >> 2];
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ lin5$0(sp);
+ tempValue = HEAP32[sp + 8 >> 2] | 0;
+ tempInt = HEAP32[sp + 12 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 12 >> 2];
HEAP32[sp + 8 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
if ((tempValue | 0) == 3) {
continue;
}
@@ -118,7 +118,7 @@ function lin5() {
function mix() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 168 | 0;
main : while (1) {
c(1);
c(2);
@@ -127,17 +127,17 @@ function mix() {
c(5);
c(6);
c(7);
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = mix$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ mix$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = mix$0(sp) | 0;
- tempValue = HEAP32[sp + 0 >> 2] | 0;
- tempInt = HEAP32[sp + 8 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 8 >> 2];
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ mix$0(sp);
+ tempValue = HEAP32[sp + 8 >> 2] | 0;
+ tempInt = HEAP32[sp + 12 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 12 >> 2];
HEAP32[sp + 8 >> 2] = 0;
+ HEAP32[sp + 12 >> 2] = 0;
if ((tempValue | 0) == 1) {
break;
}
@@ -169,17 +169,17 @@ function vars(x, y) {
y = +y;
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 32 | 0;
- HEAP32[sp + 16 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = 0;
- HEAP32[sp + 0 >> 2] = x;
- HEAPF32[sp + 8 >> 2] = y;
- sp = vars$1(sp) | 0;
- HEAP32[sp + 16 >> 2] = 0;
+ STACKTOP = STACKTOP + 152 | 0;
+ HEAP32[sp + 32 >> 2] = 0;
+ HEAP32[sp + 36 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = x;
+ HEAPF32[sp + 16 >> 2] = y;
+ vars$1(sp);
HEAP32[sp + 24 >> 2] = 0;
- HEAP32[sp + 0 >> 2] = x;
- HEAPF32[sp + 8 >> 2] = y;
- sp = vars$0(sp) | 0;
+ HEAP32[sp + 28 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = x;
+ HEAPF32[sp + 16 >> 2] = y;
+ vars$0(sp);
STACKTOP = sp;
}
function vars2(x, y) {
@@ -187,18 +187,18 @@ function vars2(x, y) {
y = +y;
var a = 0, b = +0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 48 | 0;
+ STACKTOP = STACKTOP + 152 | 0;
a = x + y;
b = y * x;
a = c(1 + a);
b = c(2 + b);
- HEAP32[sp + 32 >> 2] = 0;
HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 16 >> 2] = a;
- HEAPF32[sp + 24 >> 2] = b;
- sp = vars2$0(sp) | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
- b = +HEAPF32[sp + 24 >> 2];
+ HEAP32[sp + 44 >> 2] = 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAPF32[sp + 32 >> 2] = b;
+ vars2$0(sp);
+ a = HEAP32[sp + 24 >> 2] | 0;
+ b = +HEAPF32[sp + 32 >> 2];
STACKTOP = sp;
}
function vars3(x, y) {
@@ -206,21 +206,21 @@ function vars3(x, y) {
y = +y;
var a = 0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 40 | 0;
- HEAP32[sp + 24 >> 2] = 0;
- HEAP32[sp + 32 >> 2] = 0;
- HEAP32[sp + 16 >> 2] = a;
- HEAP32[sp + 0 >> 2] = x;
- HEAPF32[sp + 8 >> 2] = y;
- sp = vars3$1(sp) | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
- HEAP32[sp + 24 >> 2] = 0;
+ STACKTOP = STACKTOP + 160 | 0;
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAP32[sp + 8 >> 2] = x;
+ HEAPF32[sp + 16 >> 2] = y;
+ vars3$1(sp);
+ a = HEAP32[sp + 24 >> 2] | 0;
HEAP32[sp + 32 >> 2] = 0;
- HEAP32[sp + 16 >> 2] = a;
- HEAPF32[sp + 8 >> 2] = y;
- HEAP32[sp + 0 >> 2] = x;
- sp = vars3$0(sp) | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
+ HEAP32[sp + 36 >> 2] = 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAPF32[sp + 16 >> 2] = y;
+ HEAP32[sp + 8 >> 2] = x;
+ vars3$0(sp);
+ a = HEAP32[sp + 24 >> 2] | 0;
STACKTOP = sp;
}
function vars4(x, y) {
@@ -228,25 +228,25 @@ function vars4(x, y) {
y = +y;
var a = 0, b = +0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 48 | 0;
+ STACKTOP = STACKTOP + 168 | 0;
a = x + y;
- HEAP32[sp + 32 >> 2] = 0;
+ HEAP32[sp + 48 >> 2] = 0;
+ HEAP32[sp + 52 >> 2] = 0;
+ HEAPF32[sp + 16 >> 2] = y;
+ HEAP32[sp + 8 >> 2] = x;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAPF32[sp + 32 >> 2] = b;
+ vars4$1(sp);
+ b = +HEAPF32[sp + 32 >> 2];
+ a = HEAP32[sp + 24 >> 2] | 0;
HEAP32[sp + 40 >> 2] = 0;
- HEAPF32[sp + 8 >> 2] = y;
- HEAP32[sp + 0 >> 2] = x;
- HEAP32[sp + 16 >> 2] = a;
- HEAPF32[sp + 24 >> 2] = b;
- sp = vars4$1(sp) | 0;
- b = +HEAPF32[sp + 24 >> 2];
- a = HEAP32[sp + 16 >> 2] | 0;
- HEAP32[sp + 32 >> 2] = 0;
- HEAP32[sp + 40 >> 2] = 0;
- HEAP32[sp + 16 >> 2] = a;
- HEAP32[sp + 0 >> 2] = x;
- HEAPF32[sp + 24 >> 2] = b;
- sp = vars4$0(sp) | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
- b = +HEAPF32[sp + 24 >> 2];
+ HEAP32[sp + 44 >> 2] = 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAP32[sp + 8 >> 2] = x;
+ HEAPF32[sp + 32 >> 2] = b;
+ vars4$0(sp);
+ a = HEAP32[sp + 24 >> 2] | 0;
+ b = +HEAPF32[sp + 32 >> 2];
STACKTOP = sp;
}
function vars_w_stack(x, y) {
@@ -254,24 +254,61 @@ function vars_w_stack(x, y) {
y = +y;
var a = 0, b = +0, sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 72 | 0;
+ STACKTOP = STACKTOP + 208 | 0;
a = x + y;
- HEAP32[sp + 56 >> 2] = 0;
+ HEAP32[sp + 72 >> 2] = 0;
+ HEAP32[sp + 76 >> 2] = 0;
+ HEAPF32[sp + 32 >> 2] = y;
+ HEAP32[sp + 24 >> 2] = x;
+ HEAP32[sp + 40 >> 2] = a;
+ HEAPF32[sp + 48 >> 2] = b;
+ vars_w_stack$1(sp);
+ b = +HEAPF32[sp + 48 >> 2];
+ a = HEAP32[sp + 40 >> 2] | 0;
HEAP32[sp + 64 >> 2] = 0;
- HEAPF32[sp + 24 >> 2] = y;
- HEAP32[sp + 16 >> 2] = x;
- HEAP32[sp + 32 >> 2] = a;
- HEAPF32[sp + 40 >> 2] = b;
- sp = vars_w_stack$1(sp) | 0;
- b = +HEAPF32[sp + 40 >> 2];
- a = HEAP32[sp + 32 >> 2] | 0;
+ HEAP32[sp + 68 >> 2] = 0;
+ HEAP32[sp + 40 >> 2] = a;
+ HEAPF32[sp + 48 >> 2] = b;
+ vars_w_stack$0(sp);
+ a = HEAP32[sp + 40 >> 2] | 0;
+ b = +HEAPF32[sp + 48 >> 2];
+}
+function chain() {
+ var helper$0 = 0, sp = 0;
+ sp = STACKTOP;
+ STACKTOP = STACKTOP + 352 | 0;
+ helper$0 = 1;
HEAP32[sp + 56 >> 2] = 0;
- HEAP32[sp + 64 >> 2] = 0;
- HEAP32[sp + 32 >> 2] = a;
- HEAPF32[sp + 40 >> 2] = b;
- sp = vars_w_stack$0(sp) | 0;
- a = HEAP32[sp + 32 >> 2] | 0;
- b = +HEAPF32[sp + 40 >> 2];
+ HEAP32[sp + 60 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$5(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 48 >> 2] = 0;
+ HEAP32[sp + 52 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$4(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 40 >> 2] = 0;
+ HEAP32[sp + 44 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$3(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 32 >> 2] = 0;
+ HEAP32[sp + 36 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$2(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 24 >> 2] = 0;
+ HEAP32[sp + 28 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$1(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ HEAP32[sp + 8 >> 2] = helper$0;
+ chain$0(sp);
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ STACKTOP = sp;
}
function lin$0(sp) {
sp = sp | 0;
@@ -283,7 +320,6 @@ function lin$0(sp) {
c(18);
c(19);
c(20);
- return sp | 0;
}
function lin$1(sp) {
sp = sp | 0;
@@ -295,7 +331,6 @@ function lin$1(sp) {
c(10);
c(11);
c(12);
- return sp | 0;
}
function lin2$0(sp) {
sp = sp | 0;
@@ -307,7 +342,6 @@ function lin2$0(sp) {
c(18);
c(19);
c(20);
- return sp | 0;
}
function lin2$1(sp) {
sp = sp | 0;
@@ -319,7 +353,6 @@ function lin2$1(sp) {
c(10);
c(11);
c(12);
- return sp | 0;
}
function lin3$0(sp) {
sp = sp | 0;
@@ -331,11 +364,10 @@ function lin3$0(sp) {
c(18);
c(19);
c(20);
- HEAP32[sp + 0 >> 2] = 6;
- HEAP32[sp + 8 >> 2] = 10;
+ HEAP32[sp + 8 >> 2] = 6;
+ HEAP32[sp + 12 >> 2] = 10;
break OL;
} while (0);
- return sp | 0;
}
function lin3$1(sp) {
sp = sp | 0;
@@ -347,7 +379,6 @@ function lin3$1(sp) {
c(11);
c(12);
c(13);
- return sp | 0;
}
function lin4$0(sp) {
sp = sp | 0;
@@ -360,10 +391,9 @@ function lin4$0(sp) {
c(18);
c(19);
c(20);
- HEAP32[sp + 0 >> 2] = 1;
+ HEAP32[sp + 8 >> 2] = 1;
break OL;
} while (0);
- return sp | 0;
}
function lin4$1(sp) {
sp = sp | 0;
@@ -375,7 +405,6 @@ function lin4$1(sp) {
c(10);
c(11);
c(12);
- return sp | 0;
}
function lin5$0(sp) {
sp = sp | 0;
@@ -388,10 +417,9 @@ function lin5$0(sp) {
c(18);
c(19);
c(20);
- HEAP32[sp + 0 >> 2] = 3;
+ HEAP32[sp + 8 >> 2] = 3;
break OL;
} while (0);
- return sp | 0;
}
function lin5$1(sp) {
sp = sp | 0;
@@ -403,18 +431,17 @@ function lin5$1(sp) {
c(10);
c(11);
c(12);
- return sp | 0;
}
function mix$0(sp) {
sp = sp | 0;
OL : do {
c(16);
c(17);
- HEAP32[sp + 0 >> 2] = 2;
HEAP32[sp + 8 >> 2] = 2;
+ HEAP32[sp + 12 >> 2] = 2;
break OL;
c(18);
- HEAP32[sp + 0 >> 2] = 1;
+ HEAP32[sp + 8 >> 2] = 1;
break OL;
while (1) {
break;
@@ -423,14 +450,13 @@ function mix$0(sp) {
break inner;
}
c(19);
- HEAP32[sp + 0 >> 2] = 3;
+ HEAP32[sp + 8 >> 2] = 3;
break OL;
c(20);
- HEAP32[sp + 0 >> 2] = 4;
- HEAP32[sp + 8 >> 2] = 3;
+ HEAP32[sp + 8 >> 2] = 4;
+ HEAP32[sp + 12 >> 2] = 3;
break OL;
} while (0);
- return sp | 0;
}
function mix$1(sp) {
sp = sp | 0;
@@ -442,125 +468,203 @@ function mix$1(sp) {
c(13);
c(14);
c(15);
- return sp | 0;
}
function vars$0(sp) {
sp = sp | 0;
var x = 0, y = +0;
- y = +HEAPF32[sp + 8 >> 2];
- x = HEAP32[sp + 0 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
+ x = HEAP32[sp + 8 >> 2] | 0;
c(5 + (x + y));
c(6 + y * x);
c(7 + (x + y));
c(8 + y * x);
- return sp | 0;
}
function vars$1(sp) {
sp = sp | 0;
var x = 0, y = +0;
- y = +HEAPF32[sp + 8 >> 2];
- x = HEAP32[sp + 0 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
+ x = HEAP32[sp + 8 >> 2] | 0;
c(1 + (x + y));
c(2 + y * x);
c(3 + (x + y));
c(4 + y * x);
- return sp | 0;
}
function vars2$0(sp) {
sp = sp | 0;
var a = 0, b = +0;
- b = +HEAPF32[sp + 24 >> 2];
- a = HEAP32[sp + 16 >> 2] | 0;
+ b = +HEAPF32[sp + 32 >> 2];
+ a = HEAP32[sp + 24 >> 2] | 0;
a = c(3 + a);
b = c(4 + b);
a = c(5 + a);
b = c(6 + b);
- HEAP32[sp + 16 >> 2] = a;
- HEAPF32[sp + 24 >> 2] = b;
- return sp | 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAPF32[sp + 32 >> 2] = b;
}
function vars3$0(sp) {
sp = sp | 0;
var a = 0, y = +0, x = 0;
- x = HEAP32[sp + 0 >> 2] | 0;
- y = +HEAPF32[sp + 8 >> 2];
- a = HEAP32[sp + 16 >> 2] | 0;
+ x = HEAP32[sp + 8 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
+ a = HEAP32[sp + 24 >> 2] | 0;
a = c(4 + y * x);
a = c(5 + a);
a = c(6 + y * x);
a = c(7 + a);
- HEAP32[sp + 16 >> 2] = a;
- return sp | 0;
+ HEAP32[sp + 24 >> 2] = a;
}
function vars3$1(sp) {
sp = sp | 0;
var a = 0, x = 0, y = +0;
- y = +HEAPF32[sp + 8 >> 2];
- x = HEAP32[sp + 0 >> 2] | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
+ x = HEAP32[sp + 8 >> 2] | 0;
+ a = HEAP32[sp + 24 >> 2] | 0;
a = x + y;
a = c(1 + a);
a = c(2 + y * x);
a = c(3 + a);
- HEAP32[sp + 16 >> 2] = a;
- return sp | 0;
+ HEAP32[sp + 24 >> 2] = a;
}
function vars4$0(sp) {
sp = sp | 0;
var a = 0, x = 0, b = +0;
- b = +HEAPF32[sp + 24 >> 2];
- x = HEAP32[sp + 0 >> 2] | 0;
- a = HEAP32[sp + 16 >> 2] | 0;
+ b = +HEAPF32[sp + 32 >> 2];
+ x = HEAP32[sp + 8 >> 2] | 0;
+ a = HEAP32[sp + 24 >> 2] | 0;
a = c(4 + a);
a = c(5 + a);
a = c(6 + a);
b = c(7 + a + x);
- HEAP32[sp + 16 >> 2] = a;
- HEAPF32[sp + 24 >> 2] = b;
- return sp | 0;
+ HEAP32[sp + 24 >> 2] = a;
+ HEAPF32[sp + 32 >> 2] = b;
}
function vars4$1(sp) {
sp = sp | 0;
var y = +0, x = 0, a = 0, b = +0;
- b = +HEAPF32[sp + 24 >> 2];
- a = HEAP32[sp + 16 >> 2] | 0;
- x = HEAP32[sp + 0 >> 2] | 0;
- y = +HEAPF32[sp + 8 >> 2];
+ b = +HEAPF32[sp + 32 >> 2];
+ a = HEAP32[sp + 24 >> 2] | 0;
+ x = HEAP32[sp + 8 >> 2] | 0;
+ y = +HEAPF32[sp + 16 >> 2];
b = y * x;
a = c(1 + a);
a = c(2 + a);
a = c(3 + a);
- HEAPF32[sp + 24 >> 2] = b;
- HEAP32[sp + 16 >> 2] = a;
- return sp | 0;
+ HEAPF32[sp + 32 >> 2] = b;
+ HEAP32[sp + 24 >> 2] = a;
}
function vars_w_stack$0(sp) {
sp = sp | 0;
var a = 0, b = +0;
- b = +HEAPF32[sp + 40 >> 2];
- a = HEAP32[sp + 32 >> 2] | 0;
+ b = +HEAPF32[sp + 48 >> 2];
+ a = HEAP32[sp + 40 >> 2] | 0;
a = c(4 + a);
a = c(5 + a);
a = c(6 + a);
b = c(7 + a);
STACKTOP = sp;
- HEAP32[sp + 32 >> 2] = a;
- HEAPF32[sp + 40 >> 2] = b;
- return sp | 0;
+ HEAP32[sp + 40 >> 2] = a;
+ HEAPF32[sp + 48 >> 2] = b;
}
function vars_w_stack$1(sp) {
sp = sp | 0;
var y = +0, x = 0, a = 0, b = +0;
- b = +HEAPF32[sp + 40 >> 2];
- a = HEAP32[sp + 32 >> 2] | 0;
- x = HEAP32[sp + 16 >> 2] | 0;
- y = +HEAPF32[sp + 24 >> 2];
+ b = +HEAPF32[sp + 48 >> 2];
+ a = HEAP32[sp + 40 >> 2] | 0;
+ x = HEAP32[sp + 24 >> 2] | 0;
+ y = +HEAPF32[sp + 32 >> 2];
b = y * x;
a = c(1 + a);
a = c(2 + a);
a = c(3 + a);
- HEAPF32[sp + 40 >> 2] = b;
- HEAP32[sp + 32 >> 2] = a;
- return sp | 0;
+ HEAPF32[sp + 48 >> 2] = b;
+ HEAP32[sp + 40 >> 2] = a;
+}
+function chain$0(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 11 : 0) {
+ helper$0 = 0;
+ print(11);
+ }
+ if (helper$0 ? x == 12 : 0) {
+ helper$0 = 0;
+ print(12);
+ }
+ if (helper$0) {
+ helper$0 = 0;
+ print(99);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$1(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 9 : 0) {
+ helper$0 = 0;
+ print(9);
+ }
+ if (helper$0 ? x == 10 : 0) {
+ helper$0 = 0;
+ print(10);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$2(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 7 : 0) {
+ helper$0 = 0;
+ print(7);
+ }
+ if (helper$0 ? x == 8 : 0) {
+ helper$0 = 0;
+ print(8);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$3(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 5 : 0) {
+ helper$0 = 0;
+ print(5);
+ }
+ if (helper$0 ? x == 6 : 0) {
+ helper$0 = 0;
+ print(6);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$4(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 3 : 0) {
+ helper$0 = 0;
+ print(3);
+ }
+ if (helper$0 ? x == 4 : 0) {
+ helper$0 = 0;
+ print(4);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
+}
+function chain$5(sp) {
+ sp = sp | 0;
+ var helper$0 = 0;
+ helper$0 = HEAP32[sp + 8 >> 2] | 0;
+ if (helper$0 ? x == 1 : 0) {
+ helper$0 = 0;
+ print(1);
+ }
+ if (helper$0 ? x == 2 : 0) {
+ helper$0 = 0;
+ print(2);
+ }
+ HEAP32[sp + 8 >> 2] = helper$0;
}
diff --git a/tools/test-js-optimizer-asm-outline1.js b/tools/test-js-optimizer-asm-outline1.js
index 40026439..311cb206 100644
--- a/tools/test-js-optimizer-asm-outline1.js
+++ b/tools/test-js-optimizer-asm-outline1.js
@@ -230,5 +230,34 @@ function vars_w_stack(x, y) {
b = c(7+a);
STACKTOP = sp;
}
+function chain() {
+ if (x == 1) {
+ print(1);
+ } else if (x == 2) {
+ print(2);
+ } else if (x == 3) {
+ print(3);
+ } else if (x == 4) {
+ print(4);
+ } else if (x == 5) {
+ print(5);
+ } else if (x == 6) {
+ print(6);
+ } else if (x == 7) {
+ print(7);
+ } else if (x == 8) {
+ print(8);
+ } else if (x == 9) {
+ print(9);
+ } else if (x == 10) {
+ print(10);
+ } else if (x == 11) {
+ print(11);
+ } else if (x == 12) {
+ print(12);
+ } else {
+ print(99);
+ }
+}
// EMSCRIPTEN_GENERATED_FUNCTIONS
// EXTRA_INFO: { "sizeToOutline": 30, "allowCostlyOutlines": 1 }
diff --git a/tools/test-js-optimizer-asm-outline2-output.js b/tools/test-js-optimizer-asm-outline2-output.js
index 4b7bb6e2..abff54cb 100644
--- a/tools/test-js-optimizer-asm-outline2-output.js
+++ b/tools/test-js-optimizer-asm-outline2-output.js
@@ -1,7 +1,7 @@
function linear() {
var sp = 0;
sp = STACKTOP;
- STACKTOP = STACKTOP + 16 | 0;
+ STACKTOP = STACKTOP + 152 | 0;
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
@@ -11,17 +11,17 @@ function linear() {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
- HEAP32[sp + 0 >> 2] = 0;
+ HEAP32[sp + 16 >> 2] = 0;
+ HEAP32[sp + 20 >> 2] = 0;
+ linear$1(sp);
HEAP32[sp + 8 >> 2] = 0;
- sp = linear$1(sp) | 0;
- HEAP32[sp + 0 >> 2] = 0;
- HEAP32[sp + 8 >> 2] = 0;
- sp = linear$0(sp) | 0;
+ HEAP32[sp + 12 >> 2] = 0;
+ linear$0(sp);
STACKTOP = sp;
}
function _free($mem) {
$mem = $mem | 0;
- var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0;
+ var $5 = 0, $10 = 0, $16 = 0, $21 = 0, $25 = 0, $26 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $194 = 0, sp = 0, helper$0 = 0;
sp = STACKTOP;
if (($mem | 0) == 0) {
STACKTOP = sp;
@@ -37,7 +37,9 @@ function _free($mem) {
}
$16 = $mem + (($10 & -8) - 8) | 0;
L621 : do {
- if (($10 & 1 | 0) == 0) {
+ helper$0 = 1;
+ if (helper$0 ? ($10 & 1 | 0) == 0 : 0) {
+ helper$0 = 0;
$21 = HEAP32[($mem - 8 | 0) >> 2] | 0;
if (($10 & 3 | 0) == 0) {
return;
@@ -47,24 +49,24 @@ function _free($mem) {
if (($mem + (-8 - $21 | 0) | 0) >>> 0 < $5 >>> 0) {
_abort();
}
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
- HEAP32[sp + 40 >> 2] = $25;
- HEAP32[sp + 0 >> 2] = $mem;
- HEAP32[sp + 16 >> 2] = $10;
- HEAP32[sp + 48 >> 2] = $26;
- HEAP32[sp + 32 >> 2] = $21;
- HEAP32[sp + 8 >> 2] = $5;
- HEAP32[sp + 216 >> 2] = $p_0;
- HEAP32[sp + 208 >> 2] = $psize_0;
- sp = _free$1(sp) | 0;
- $p_0 = HEAP32[sp + 216 >> 2] | 0;
- $psize_0 = HEAP32[sp + 208 >> 2] | 0;
- tempValue = HEAP32[sp + 632 >> 2] | 0;
- tempInt = HEAP32[sp + 640 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 640 >> 2];
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
+ HEAP32[sp + 672 >> 2] = 0;
+ HEAP32[sp + 676 >> 2] = 0;
+ HEAP32[sp + 48 >> 2] = $25;
+ HEAP32[sp + 8 >> 2] = $mem;
+ HEAP32[sp + 24 >> 2] = $10;
+ HEAP32[sp + 56 >> 2] = $26;
+ HEAP32[sp + 40 >> 2] = $21;
+ HEAP32[sp + 16 >> 2] = $5;
+ HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 216 >> 2] = $psize_0;
+ _free$1(sp);
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ tempValue = HEAP32[sp + 672 >> 2] | 0;
+ tempInt = HEAP32[sp + 676 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 676 >> 2];
+ HEAP32[sp + 672 >> 2] = 0;
+ HEAP32[sp + 676 >> 2] = 0;
if ((tempValue | 0) == 5) {
return;
}
@@ -79,7 +81,9 @@ function _free($mem) {
}
}
}
- } else {
+ }
+ if (helper$0) {
+ helper$0 = 0;
$p_0 = $mem - 8 | 0;
$psize_0 = $10 & -8;
}
@@ -92,21 +96,21 @@ function _free($mem) {
if (($194 & 1 | 0) == 0) {
_abort();
}
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
- HEAP32[sp + 232 >> 2] = $194;
- HEAP32[sp + 24 >> 2] = $16;
- HEAP32[sp + 208 >> 2] = $psize_0;
- HEAP32[sp + 216 >> 2] = $p_0;
- HEAP32[sp + 224 >> 2] = $189;
- HEAP32[sp + 0 >> 2] = $mem;
- HEAP32[sp + 16 >> 2] = $10;
- sp = _free$2(sp) | 0;
- tempValue = HEAP32[sp + 632 >> 2] | 0;
- tempInt = HEAP32[sp + 640 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 640 >> 2];
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
+ HEAP32[sp + 680 >> 2] = 0;
+ HEAP32[sp + 684 >> 2] = 0;
+ HEAP32[sp + 240 >> 2] = $194;
+ HEAP32[sp + 32 >> 2] = $16;
+ HEAP32[sp + 216 >> 2] = $psize_0;
+ HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 232 >> 2] = $189;
+ HEAP32[sp + 8 >> 2] = $mem;
+ HEAP32[sp + 24 >> 2] = $10;
+ _free$2(sp);
+ tempValue = HEAP32[sp + 680 >> 2] | 0;
+ tempInt = HEAP32[sp + 684 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 684 >> 2];
+ HEAP32[sp + 680 >> 2] = 0;
+ HEAP32[sp + 684 >> 2] = 0;
if ((tempValue | 0) == 5) {
return;
}
@@ -126,7 +130,6 @@ function linear$0(sp) {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
- return sp | 0;
}
function linear$1(sp) {
sp = sp | 0;
@@ -143,19 +146,18 @@ function linear$1(sp) {
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
cheez(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
- return sp | 0;
}
function _free$0(sp) {
sp = sp | 0;
- var $16 = 0, $220 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $227 = 0, $194 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0, $psize_1 = 0;
- $psize_1 = HEAP32[sp + 416 >> 2] | 0;
- $10 = HEAP32[sp + 16 >> 2] | 0;
- $mem = HEAP32[sp + 0 >> 2] | 0;
- $194 = HEAP32[sp + 232 >> 2] | 0;
- $189 = HEAP32[sp + 224 >> 2] | 0;
- $p_0 = HEAP32[sp + 216 >> 2] | 0;
- $psize_0 = HEAP32[sp + 208 >> 2] | 0;
- $16 = HEAP32[sp + 24 >> 2] | 0;
+ var $16 = 0, $220 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $227 = 0, $194 = 0, helper$2 = 0, $233 = 0, $mem = 0, $10 = 0, $236 = 0, $_pre_phi305 = 0, $267 = 0, $270 = 0, $273 = 0, $294 = 0, $299 = 0, $R7_1 = 0, $R7_0 = 0, $RP9_0 = 0, $301 = 0, $302 = 0, $305 = 0, $306 = 0, $278 = 0, $320 = 0, $351 = 0, $364 = 0, $psize_1 = 0;
+ $psize_1 = HEAP32[sp + 424 >> 2] | 0;
+ $10 = HEAP32[sp + 24 >> 2] | 0;
+ $mem = HEAP32[sp + 8 >> 2] | 0;
+ $194 = HEAP32[sp + 240 >> 2] | 0;
+ $189 = HEAP32[sp + 232 >> 2] | 0;
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $16 = HEAP32[sp + 32 >> 2] | 0;
OL : do {
if (($16 | 0) == (HEAP32[25] | 0)) {
$220 = (HEAP32[22] | 0) + $psize_0 | 0;
@@ -163,12 +165,14 @@ function _free$0(sp) {
HEAP32[25] = $p_0;
HEAP32[$p_0 + 4 >> 2] = $220 | 1;
HEAP32[$189 + $220 >> 2] = $220;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 664 >> 2] = 5;
break OL;
}
$227 = ($194 & -8) + $psize_0 | 0;
L726 : do {
- if ($194 >>> 0 < 256) {
+ helper$2 = 1;
+ if (helper$2 ? $194 >>> 0 < 256 : 0) {
+ helper$2 = 0;
$233 = HEAP32[$mem + ($10 & -8) >> 2] | 0;
$236 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0;
do {
@@ -202,7 +206,9 @@ function _free$0(sp) {
} while (0);
HEAP32[$233 + 12 >> 2] = $236;
HEAP32[$_pre_phi305 >> 2] = $233;
- } else {
+ }
+ if (helper$2) {
+ helper$2 = 0;
$267 = $mem + (($10 & -8) - 8) | 0;
$270 = HEAP32[$mem + (($10 & -8) + 16) >> 2] | 0;
$273 = HEAP32[$mem + ($10 & -8 | 4) >> 2] | 0;
@@ -323,40 +329,39 @@ function _free$0(sp) {
HEAP32[$189 + $227 >> 2] = $227;
if (($p_0 | 0) != (HEAP32[25] | 0)) {
$psize_1 = $227;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 664 >> 2] = 1;
break OL;
}
HEAP32[22] = $227;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 664 >> 2] = 5;
break OL;
} while (0);
- HEAP32[sp + 416 >> 2] = $psize_1;
- return sp | 0;
+ HEAP32[sp + 424 >> 2] = $psize_1;
}
function _free$1(sp) {
sp = sp | 0;
var $25 = 0, $mem = 0, $10 = 0, $26 = 0, $21 = 0, $37 = 0, $40 = 0, $5 = 0, $_pre_phi307 = 0, $69 = 0, $72 = 0, $75 = 0, $95 = 0, $100 = 0, $R_1 = 0, $R_0 = 0, $RP_0 = 0, $102 = 0, $103 = 0, $106 = 0, $107 = 0, $80 = 0, $120 = 0, $151 = 0, $164 = 0, $p_0 = 0, $psize_0 = 0;
- $psize_0 = HEAP32[sp + 208 >> 2] | 0;
- $p_0 = HEAP32[sp + 216 >> 2] | 0;
- $5 = HEAP32[sp + 8 >> 2] | 0;
- $21 = HEAP32[sp + 32 >> 2] | 0;
- $26 = HEAP32[sp + 48 >> 2] | 0;
- $10 = HEAP32[sp + 16 >> 2] | 0;
- $mem = HEAP32[sp + 0 >> 2] | 0;
- $25 = HEAP32[sp + 40 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ $5 = HEAP32[sp + 16 >> 2] | 0;
+ $21 = HEAP32[sp + 40 >> 2] | 0;
+ $26 = HEAP32[sp + 56 >> 2] | 0;
+ $10 = HEAP32[sp + 24 >> 2] | 0;
+ $mem = HEAP32[sp + 8 >> 2] | 0;
+ $25 = HEAP32[sp + 48 >> 2] | 0;
OL : do {
if (($25 | 0) == (HEAP32[25] | 0)) {
if ((HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & 3 | 0) != 3) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
HEAP32[22] = $26;
HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] & -2;
HEAP32[$mem + ((-8 - $21 | 0) + 4) >> 2] = $26 | 1;
HEAP32[($mem + (($10 & -8) - 8) | 0) >> 2] = $26;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 672 >> 2] = 5;
break OL;
}
if ($21 >>> 0 < 256) {
@@ -377,7 +382,7 @@ function _free$1(sp) {
HEAP32[20] = HEAP32[20] & (1 << ($21 >>> 3) ^ -1);
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
do {
@@ -398,7 +403,7 @@ function _free$1(sp) {
HEAP32[$_pre_phi307 >> 2] = $37;
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
$69 = $mem + (-8 - $21 | 0) | 0;
@@ -465,7 +470,7 @@ function _free$1(sp) {
if (($72 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
$120 = 384 + (HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] << 2) | 0;
@@ -478,8 +483,8 @@ function _free$1(sp) {
HEAP32[21] = HEAP32[21] & (1 << HEAP32[($mem + ((-8 - $21 | 0) + 28) | 0) >> 2] ^ -1);
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 2;
- HEAP32[sp + 640 >> 2] = 2;
+ HEAP32[sp + 672 >> 2] = 2;
+ HEAP32[sp + 676 >> 2] = 2;
break OL;
} else {
if ($72 >>> 0 < (HEAP32[24] | 0) >>> 0) {
@@ -493,8 +498,8 @@ function _free$1(sp) {
if (($R_1 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 2;
- HEAP32[sp + 640 >> 2] = 2;
+ HEAP32[sp + 672 >> 2] = 2;
+ HEAP32[sp + 676 >> 2] = 2;
break OL;
}
}
@@ -519,7 +524,7 @@ function _free$1(sp) {
if (($164 | 0) == 0) {
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
if ($164 >>> 0 < (HEAP32[24] | 0) >>> 0) {
@@ -529,27 +534,28 @@ function _free$1(sp) {
HEAP32[$164 + 24 >> 2] = $R_1;
$p_0 = $25;
$psize_0 = $26;
- HEAP32[sp + 632 >> 2] = 1;
+ HEAP32[sp + 672 >> 2] = 1;
break OL;
}
} while (0);
- HEAP32[sp + 216 >> 2] = $p_0;
- HEAP32[sp + 208 >> 2] = $psize_0;
- return sp | 0;
+ HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 216 >> 2] = $psize_0;
}
function _free$2(sp) {
sp = sp | 0;
- var $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0;
- $10 = HEAP32[sp + 16 >> 2] | 0;
- $mem = HEAP32[sp + 0 >> 2] | 0;
- $189 = HEAP32[sp + 224 >> 2] | 0;
- $p_0 = HEAP32[sp + 216 >> 2] | 0;
- $psize_0 = HEAP32[sp + 208 >> 2] | 0;
- $16 = HEAP32[sp + 24 >> 2] | 0;
- $194 = HEAP32[sp + 232 >> 2] | 0;
+ var helper$1 = 0, $194 = 0, $16 = 0, $204 = 0, $psize_0 = 0, $p_0 = 0, $189 = 0, $mem = 0, $10 = 0, $psize_1 = 0, $390 = 0, $396 = 0, $F16_0 = 0, $_pre_phi = 0, $404 = 0, $414 = 0, $415 = 0, $I18_0 = 0, $428 = 0, $436 = 0, $443 = 0, $447 = 0, $448 = 0, $463 = 0, $K19_0 = 0, $T_0 = 0, $472 = 0, $473 = 0, label = 0, $486 = 0, $487 = 0, $489 = 0, $501 = 0, $sp_0_in_i = 0, $sp_0_i = 0;
+ $10 = HEAP32[sp + 24 >> 2] | 0;
+ $mem = HEAP32[sp + 8 >> 2] | 0;
+ $189 = HEAP32[sp + 232 >> 2] | 0;
+ $p_0 = HEAP32[sp + 224 >> 2] | 0;
+ $psize_0 = HEAP32[sp + 216 >> 2] | 0;
+ $16 = HEAP32[sp + 32 >> 2] | 0;
+ $194 = HEAP32[sp + 240 >> 2] | 0;
OL : do {
do {
- if (($194 & 2 | 0) == 0) {
+ helper$1 = 1;
+ if (helper$1 ? ($194 & 2 | 0) == 0 : 0) {
+ helper$1 = 0;
if (($16 | 0) == (HEAP32[26] | 0)) {
$204 = (HEAP32[23] | 0) + $psize_0 | 0;
HEAP32[23] = $204;
@@ -560,38 +566,40 @@ function _free$2(sp) {
HEAP32[22] = 0;
}
if ($204 >>> 0 <= (HEAP32[27] | 0) >>> 0) {
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
}
_sys_trim(0) | 0;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
}
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
- HEAP32[sp + 24 >> 2] = $16;
- HEAP32[sp + 208 >> 2] = $psize_0;
- HEAP32[sp + 216 >> 2] = $p_0;
- HEAP32[sp + 224 >> 2] = $189;
- HEAP32[sp + 232 >> 2] = $194;
- HEAP32[sp + 0 >> 2] = $mem;
- HEAP32[sp + 16 >> 2] = $10;
- HEAP32[sp + 416 >> 2] = $psize_1;
- sp = _free$0(sp) | 0;
- $psize_1 = HEAP32[sp + 416 >> 2] | 0;
- tempValue = HEAP32[sp + 632 >> 2] | 0;
- tempInt = HEAP32[sp + 640 >> 2] | 0;
- tempDouble = +HEAPF32[sp + 640 >> 2];
- HEAP32[sp + 632 >> 2] = 0;
- HEAP32[sp + 640 >> 2] = 0;
+ HEAP32[sp + 664 >> 2] = 0;
+ HEAP32[sp + 668 >> 2] = 0;
+ HEAP32[sp + 32 >> 2] = $16;
+ HEAP32[sp + 216 >> 2] = $psize_0;
+ HEAP32[sp + 224 >> 2] = $p_0;
+ HEAP32[sp + 232 >> 2] = $189;
+ HEAP32[sp + 240 >> 2] = $194;
+ HEAP32[sp + 8 >> 2] = $mem;
+ HEAP32[sp + 24 >> 2] = $10;
+ HEAP32[sp + 424 >> 2] = $psize_1;
+ _free$0(sp);
+ $psize_1 = HEAP32[sp + 424 >> 2] | 0;
+ tempValue = HEAP32[sp + 664 >> 2] | 0;
+ tempInt = HEAP32[sp + 668 >> 2] | 0;
+ tempDouble = +HEAPF32[sp + 668 >> 2];
+ HEAP32[sp + 664 >> 2] = 0;
+ HEAP32[sp + 668 >> 2] = 0;
if ((tempValue | 0) == 5) {
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
}
if ((tempValue | 0) == 1) {
break;
}
- } else {
+ }
+ if (helper$1) {
+ helper$1 = 0;
HEAP32[($mem + (($10 & -8) - 4) | 0) >> 2] = $194 & -2;
HEAP32[$p_0 + 4 >> 2] = $psize_0 | 1;
HEAP32[$189 + $psize_0 >> 2] = $psize_0;
@@ -620,7 +628,7 @@ function _free$2(sp) {
HEAP32[$F16_0 + 12 >> 2] = $p_0;
HEAP32[$p_0 + 8 >> 2] = $F16_0;
HEAP32[$p_0 + 12 >> 2] = 120 + ($390 << 1 << 2) | 0;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
}
$414 = $p_0;
@@ -707,7 +715,7 @@ function _free$2(sp) {
if (($501 | 0) == 0) {
$sp_0_in_i = 536;
} else {
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
}
while (1) {
@@ -720,9 +728,8 @@ function _free$2(sp) {
}
HEAP32[28] = -1;
STACKTOP = sp;
- HEAP32[sp + 632 >> 2] = 5;
+ HEAP32[sp + 680 >> 2] = 5;
break OL;
} while (0);
- return sp | 0;
}
diff --git a/tools/test-js-optimizer-asm-outline3-output.js b/tools/test-js-optimizer-asm-outline3-output.js
new file mode 100644
index 00000000..5cc0f48d
--- /dev/null
+++ b/tools/test-js-optimizer-asm-outline3-output.js
@@ -0,0 +1,28 @@
+function _memset(ptr, value, num) {
+ ptr = ptr | 0;
+ value = value | 0;
+ num = num | 0;
+ var stop = 0, value4 = 0, unaligned = 0;
+ stop = ptr + num | 0;
+ if ((num | 0) >= 20) {
+ value = value & 255;
+ unaligned = ptr & 3;
+ value4 = value | value << 8 | value << 16 | value << 24;
+ if (unaligned) {
+ unaligned = ptr + 4 - unaligned | 0;
+ while ((ptr | 0) < (unaligned | 0)) {
+ HEAP8[ptr] = value;
+ ptr = ptr + 1 | 0;
+ }
+ }
+ while ((ptr | 0) < (stop & ~3 | 0)) {
+ HEAP32[ptr >> 2] = value4;
+ ptr = ptr + 4 | 0;
+ }
+ }
+ while ((ptr | 0) < (stop | 0)) {
+ HEAP8[ptr] = value;
+ ptr = ptr + 1 | 0;
+ }
+}
+
diff --git a/tools/test-js-optimizer-asm-outline3.js b/tools/test-js-optimizer-asm-outline3.js
new file mode 100644
index 00000000..119447d8
--- /dev/null
+++ b/tools/test-js-optimizer-asm-outline3.js
@@ -0,0 +1,30 @@
+function _memset(ptr, value, num) {
+ ptr = ptr | 0;
+ value = value | 0;
+ num = num | 0;
+ var stop = 0, value4 = 0, stop4 = 0, unaligned = 0;
+ stop = ptr + num | 0;
+ if ((num | 0) >= 20) {
+ value = value & 255;
+ unaligned = ptr & 3;
+ value4 = value | value << 8 | value << 16 | value << 24;
+ stop4 = stop & ~3;
+ if (unaligned) {
+ unaligned = ptr + 4 - unaligned | 0;
+ while ((ptr | 0) < (unaligned | 0)) {
+ HEAP8[ptr] = value;
+ ptr = ptr + 1 | 0;
+ }
+ }
+ while ((ptr | 0) < (stop4 | 0)) {
+ HEAP32[ptr >> 2] = value4;
+ ptr = ptr + 4 | 0;
+ }
+ }
+ while ((ptr | 0) < (stop | 0)) {
+ HEAP8[ptr] = value;
+ ptr = ptr + 1 | 0;
+ }
+}
+// EMSCRIPTEN_GENERATED_FUNCTIONS
+// EXTRA_INFO: { "sizeToOutline": 100 }