summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rwxr-xr-xemscripten.py33
-rw-r--r--src/library.js339
-rw-r--r--src/library_browser.js4
-rw-r--r--src/library_gl.js70
-rw-r--r--src/library_sdl.js14
-rw-r--r--system/include/libc/sys/dirent.h1
-rw-r--r--tests/dirent/test_readdir.c132
-rw-r--r--tests/fcntl-misc/src.c2
-rw-r--r--tests/fcntl-open/output.txt10
-rw-r--r--tests/fcntl-open/src.c64
-rwxr-xr-xtests/runner.py331
-rw-r--r--tests/unistd/isatty.c38
-rw-r--r--tests/unistd/isatty.js5
-rw-r--r--tests/unistd/isatty.out10
-rw-r--r--tests/unistd/ttyname.c76
-rw-r--r--tests/unistd/ttyname.js1
-rw-r--r--tests/unistd/ttyname.out5
-rw-r--r--tests/utime/test_utime.c53
-rw-r--r--tools/js-optimizer.js6
-rw-r--r--tools/js_optimizer.py24
-rw-r--r--tools/shared.py2
-rw-r--r--tools/test-js-optimizer-asm-pre-output.js3
-rw-r--r--tools/test-js-optimizer-asm-pre.js3
24 files changed, 844 insertions, 383 deletions
diff --git a/AUTHORS b/AUTHORS
index 752e7593..021240e2 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -87,3 +87,4 @@ a license to everyone to use it as detailed in LICENSE.)
* Manfred Manik Nerurkar <nerurkar*at*made-apps.biz> (copyright owned by MADE, GmbH)
* Joseph Gentle <me@josephg.com>
* Douglas T. Crosher <dtc-moz@scieneer.com> (copyright owned by Mozilla Founcation)
+* Soeren Balko <soeren.balko@gmail.com>
diff --git a/emscripten.py b/emscripten.py
index 1536bcdf..3e3538e9 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -44,20 +44,25 @@ MIN_CHUNK_SIZE = 1024*1024
MAX_CHUNK_SIZE = float(os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or 'inf') # configuring this is just for debugging purposes
def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, temp_files, DEBUG)):
- funcs_file = temp_files.get('.func_%d.ll' % i).name
- f = open(funcs_file, 'w')
- f.write(funcs)
- funcs = None
- f.write('\n')
- f.write(meta)
- f.close()
- out = jsrun.run_js(
- compiler,
- engine=compiler_engine,
- args=[settings_file, funcs_file, 'funcs', forwarded_file] + libraries,
- stdout=subprocess.PIPE,
- cwd=path_from_root('src'))
- tempfiles.try_delete(funcs_file)
+ try:
+ funcs_file = temp_files.get('.func_%d.ll' % i).name
+ f = open(funcs_file, 'w')
+ f.write(funcs)
+ funcs = None
+ f.write('\n')
+ f.write(meta)
+ f.close()
+ out = jsrun.run_js(
+ compiler,
+ engine=compiler_engine,
+ args=[settings_file, funcs_file, 'funcs', forwarded_file] + libraries,
+ stdout=subprocess.PIPE,
+ cwd=path_from_root('src'))
+ except KeyboardInterrupt:
+ # Python 2.7 seems to lock up when a child process throws KeyboardInterrupt
+ raise Exception()
+ finally:
+ tempfiles.try_delete(funcs_file)
if DEBUG: print >> sys.stderr, '.'
return out
diff --git a/src/library.js b/src/library.js
index 19452bb1..fd883e82 100644
--- a/src/library.js
+++ b/src/library.js
@@ -588,8 +588,11 @@ LibraryManager.library = {
// Create the I/O devices.
var devFolder = FS.createFolder('/', 'dev', true, true);
var stdin = FS.createDevice(devFolder, 'stdin', input);
+ stdin.isTerminal = !stdinOverridden;
var stdout = FS.createDevice(devFolder, 'stdout', null, output);
+ stdout.isTerminal = !stdoutOverridden;
var stderr = FS.createDevice(devFolder, 'stderr', null, error);
+ stderr.isTerminal = !stderrOverridden;
FS.createDevice(devFolder, 'tty', input, output);
FS.createDevice(devFolder, 'null', function(){}, function(){});
@@ -601,7 +604,6 @@ LibraryManager.library = {
isRead: true,
isWrite: false,
isAppend: false,
- isTerminal: !stdinOverridden,
error: false,
eof: false,
ungotten: []
@@ -613,7 +615,6 @@ LibraryManager.library = {
isRead: false,
isWrite: true,
isAppend: false,
- isTerminal: !stdoutOverridden,
error: false,
eof: false,
ungotten: []
@@ -625,7 +626,6 @@ LibraryManager.library = {
isRead: false,
isWrite: true,
isAppend: false,
- isTerminal: !stderrOverridden,
error: false,
eof: false,
ungotten: []
@@ -737,7 +737,8 @@ LibraryManager.library = {
// int closedir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/closedir.html
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
- return ___setErrNo(ERRNO_CODES.EBADF);
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
} else {
_free(FS.streams[dirp].currentEntry);
FS.streams[dirp] = null;
@@ -749,7 +750,8 @@ LibraryManager.library = {
// long int telldir(DIR *dirp);
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/telldir.html
if (!FS.streams[dirp] || !FS.streams[dirp].object.isFolder) {
- return ___setErrNo(ERRNO_CODES.EBADF);
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
} else {
return FS.streams[dirp].position;
}
@@ -865,10 +867,6 @@ LibraryManager.library = {
}
var file = FS.findObject(Pointer_stringify(path));
if (file === null) return -1;
- if (!file.write) {
- ___setErrNo(ERRNO_CODES.EPERM);
- return -1;
- }
file.timestamp = time;
return 0;
},
@@ -1213,7 +1211,7 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EEXIST);
return -1;
}
- if ((isWrite || isCreate || isTruncate) && target.isFolder) {
+ if ((isWrite || isTruncate) && target.isFolder) {
___setErrNo(ERRNO_CODES.EISDIR);
return -1;
}
@@ -1381,7 +1379,7 @@ LibraryManager.library = {
posix_fallocate: function(fd, offset, len) {
// int posix_fallocate(int fd, off_t offset, off_t len);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/posix_fallocate.html
- if (!FS.streams[fd] || FS.streams[fd].link ||
+ if (!FS.streams[fd] || !FS.streams[fd].isWrite || FS.streams[fd].link ||
FS.streams[fd].isFolder || FS.streams[fd].isDevice) {
___setErrNo(ERRNO_CODES.EBADF);
return -1;
@@ -1688,13 +1686,16 @@ LibraryManager.library = {
isatty: function(fildes) {
// int isatty(int fildes);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/isatty.html
- if (!FS.streams[fildes]) {
+ var stream = FS.streams[fildes];
+ if (!stream) {
___setErrNo(ERRNO_CODES.EBADF);
return 0;
}
- if (FS.streams[fildes].isTerminal) return 1;
- ___setErrNo(ERRNO_CODES.ENOTTY);
- return 0;
+ if (!stream.object.isTerminal) {
+ ___setErrNo(ERRNO_CODES.ENOTTY);
+ return 0;
+ }
+ return 1;
},
lchown__deps: ['chown'],
lchown: function(path, owner, group) {
@@ -1916,30 +1917,21 @@ LibraryManager.library = {
if (!_ttyname.ret) _ttyname.ret = _malloc(256);
return _ttyname_r(fildes, _ttyname.ret, 256) ? 0 : _ttyname.ret;
},
- ttyname_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
+ ttyname_r__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'isatty'],
ttyname_r: function(fildes, name, namesize) {
// int ttyname_r(int fildes, char *name, size_t namesize);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html
var stream = FS.streams[fildes];
+ var ttyname = '/dev/tty';
if (!stream) {
return ___setErrNo(ERRNO_CODES.EBADF);
- } else {
- var object = stream.object;
- if (!object.isDevice || !object.input || !object.output) {
- return ___setErrNo(ERRNO_CODES.ENOTTY);
- } else {
- var ret = stream.path;
- if (namesize < ret.length + 1) {
- return ___setErrNo(ERRNO_CODES.ERANGE);
- } else {
- for (var i = 0; i < ret.length; i++) {
- {{{ makeSetValue('name', 'i', 'ret.charCodeAt(i)', 'i8') }}}
- }
- {{{ makeSetValue('name', 'i', '0', 'i8') }}}
- return 0;
- }
- }
+ } else if (!_isatty(fildes)) {
+ return ___setErrNo(ERRNO_CODES.ENOTTY);
+ } else if (namesize < ttyname.length + 1) {
+ return ___setErrNo(ERRNO_CODES.ERANGE);
}
+ writeStringToMemory(ttyname, name);
+ return 0;
},
symlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
symlink: function(path1, path2) {
@@ -3191,7 +3183,7 @@ LibraryManager.library = {
var flush = function(filedes) {
// Right now we write all data directly, except for output devices.
if (FS.streams[filedes] && FS.streams[filedes].object.output) {
- if (!FS.streams[filedes].isTerminal) { // don't flush terminals, it would cause a \n to also appear
+ if (!FS.streams[filedes].object.isTerminal) { // don't flush terminals, it would cause a \n to also appear
FS.streams[filedes].object.output(null);
}
}
@@ -5743,8 +5735,11 @@ LibraryManager.library = {
rintf: 'rint',
lrint: 'rint',
lrintf: 'rint',
- llrint: 'rint',
- llrintf: 'rint',
+ llrint: function(x) {
+ x = (x < 0) ? -Math.round(-x) : Math.round(x);
+ {{{ makeStructuralReturn(splitI64('x')) }}};
+ },
+ llrintf: 'llrint',
nearbyint: 'rint',
nearbyintf: 'rint',
trunc: function(x) {
@@ -6232,10 +6227,282 @@ LibraryManager.library = {
},
strftime_l: 'strftime', // no locale support yet
+ strptime__deps: ['__tm_struct_layout'],
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
- // TODO: Implement.
+ var pattern = Pointer_stringify(format);
+
+ // escape special characters
+ // TODO: not sure we really need to escape all of these in JS regexps
+ var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.';
+ for (var i=0, ii=SPECIAL_CHARS.length; i<ii; ++i) {
+ pattern = pattern.replace(new RegExp('\\'+SPECIAL_CHARS[i], 'g'), '\\'+SPECIAL_CHARS[i]);
+ }
+
+ // reduce number of matchers
+ var EQUIVALENT_MATCHERS = {
+ '%A': '%a',
+ '%B': '%b',
+ '%c': '%x\\s+%X',
+ '%D': '%m\\/%d\\/%y',
+ '%e': '%d',
+ '%h': '%b',
+ '%R': '%H\\:%M',
+ '%r': '%I\\:%M\\:%S\\s%p',
+ '%T': '%H\\:%M\\:%S',
+ '%x': '%m\\/%d\\/(?:%y|%Y)',
+ '%X': '%H\\:%M\\:%S'
+ };
+ for (var matcher in EQUIVALENT_MATCHERS) {
+ pattern = pattern.replace(matcher, EQUIVALENT_MATCHERS[matcher]);
+ }
+
+ // TODO: take care of locale
+
+ var DATE_PATTERNS = {
+ /* weeday name */ '%a': '(?:Sun(?:day)?)|(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)',
+ /* month name */ '%b': '(?:Jan(?:uary)?)|(?:Feb(?:ruary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|May|(?:Jun(?:e)?)|(?:Jul(?:y)?)|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)',
+ /* century */ '%C': '\\d\\d',
+ /* day of month */ '%d': '0[1-9]|[1-9](?!\\d)|1\\d|2\\d|30|31',
+ /* hour (24hr) */ '%H': '\\d(?!\\d)|[0,1]\\d|20|21|22|23',
+ /* hour (12hr) */ '%I': '\\d(?!\\d)|0\\d|10|11|12',
+ /* day of year */ '%j': '00[1-9]|0?[1-9](?!\\d)|0?[1-9]\\d(?!\\d)|[1,2]\\d\\d|3[0-6]\\d',
+ /* month */ '%m': '0[1-9]|[1-9](?!\\d)|10|11|12',
+ /* minutes */ '%M': '0\\d|\\d(?!\\d)|[1-5]\\d',
+ /* whitespace */ '%n': '\\s',
+ /* AM/PM */ '%p': 'AM|am|PM|pm|A\\.M\\.|a\\.m\\.|P\\.M\\.|p\\.m\\.',
+ /* seconds */ '%S': '0\\d|\\d(?!\\d)|[1-5]\\d|60',
+ /* week number */ '%U': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53',
+ /* week number */ '%W': '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53',
+ /* weekday number */ '%w': '[0-6]',
+ /* 2-digit year */ '%y': '\\d\\d',
+ /* 4-digit year */ '%Y': '\\d\\d\\d\\d',
+ /* % */ '%%': '%',
+ /* whitespace */ '%t': '\\s',
+ };
+
+ 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]+')');
+ }
+
+ // take care of capturing groups
+ var capture = [];
+ for (var i=pattern.indexOf('%'); i>=0; i=pattern.indexOf('%')) {
+ capture.push(pattern[i+1]);
+ pattern = pattern.replace(new RegExp('\\%'+pattern[i+1], 'g'), '');
+ }
+
+ var matches = new RegExp('^'+pattern).exec(Pointer_stringify(buf))
+ // Module['print'](Pointer_stringify(buf)+ ' is matched by '+((new RegExp('^'+pattern)).source)+' into: '+JSON.stringify(matches));
+
+ var initDate = function() {
+ var fixup = function(value, min, max) {
+ return (typeof value !== 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min);
+ };
+
+ return {
+ year: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32') }}} + 1900 , 1970, 9999),
+ month: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32') }}}, 0, 11),
+ day: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32') }}}, 1, 31),
+ hour: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32') }}}, 0, 23),
+ min: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32') }}}, 0, 59),
+ sec: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32') }}}, 0, 59)
+ };
+ };
+
+ if (matches) {
+ var date = initDate();
+ var value;
+
+ var getMatch = function(symbol) {
+ var pos = capture.indexOf(symbol);
+ // check if symbol appears in regexp
+ if (pos >= 0) {
+ // return matched value or null (falsy!) for non-matches
+ return matches[pos+1];
+ }
+ return;
+ }
+
+ // seconds
+ if ((value=getMatch('S'))) {
+ date.sec = parseInt(value);
+ }
+
+ // minutes
+ if ((value=getMatch('M'))) {
+ date.min = parseInt(value);
+ }
+
+ // hours
+ if ((value=getMatch('H'))) {
+ // 24h clock
+ date.hour = parseInt(value);
+ } else if ((value = getMatch('I'))) {
+ // AM/PM clock
+ var hour = parseInt(value);
+ if ((value=getMatch('p'))) {
+ hour += value.toUpperCase()[0] === 'P' ? 12 : 0;
+ }
+ date.hour = hour;
+ }
+
+ // year
+ if ((value=getMatch('Y'))) {
+ // parse from four-digit year
+ date.year = parseInt(value);
+ } else if ((value=getMatch('y'))) {
+ // parse from two-digit year...
+ var year = parseInt(value);
+ if ((value=getMatch('C'))) {
+ // ...and century
+ year += parseInt(value)*100;
+ } else {
+ // ...and rule-of-thumb
+ year += year<69 ? 2000 : 1900;
+ }
+ date.year = year;
+ }
+
+ // month
+ if ((value=getMatch('m'))) {
+ // parse from month number
+ date.month = parseInt(value)-1;
+ } else if ((value=getMatch('b'))) {
+ // parse from month name
+ date.month = MONTH_NUMBERS[value.substring(0,3).toUpperCase()] || 0;
+ // TODO: derive month from day in year+year, week number+day of week+year
+ }
+
+ // day
+ if ((value=getMatch('d'))) {
+ // get day of month directly
+ date.day = parseInt(value);
+ } else if ((value=getMatch('j'))) {
+ // get day of month from day of year ...
+ var day = parseInt(value);
+ 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]) {
+ date.day = day-daysUntilMonth;
+ }
+ }
+ } else if ((value=getMatch('a'))) {
+ // get day of month from weekday ...
+ var weekDay = value.substring(0,3).toUpperCase();
+ if ((value=getMatch('U'))) {
+ // ... and week number (Sunday being first day of week)
+ // Week number of the year (Sunday as the first day of the week) as a decimal number [00,53].
+ // All days in a new year preceding the first Sunday are considered to be in week 0.
+ var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay];
+ var weekNumber = parseInt(value);
+
+ // January 1st
+ var janFirst = new Date(date.year, 0, 1);
+ var endDate;
+ if (janFirst.getDay() === 0) {
+ // Jan 1st is a Sunday, and, hence in the 1st CW
+ 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));
+ }
+ date.day = endDate.getDate();
+ date.month = endDate.getMonth();
+ } else if ((value=getMatch('W'))) {
+ // ... and week number (Monday being first day of week)
+ // Week number of the year (Monday as the first day of the week) as a decimal number [00,53].
+ // All days in a new year preceding the first Monday are considered to be in week 0.
+ var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay];
+ var weekNumber = parseInt(value);
+
+ // January 1st
+ var janFirst = new Date(date.year, 0, 1);
+ var endDate;
+ if (janFirst.getDay()===1) {
+ // Jan 1st is a Monday, and, hence in the 1st CW
+ 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));
+ }
+
+ date.day = endDate.getDate();
+ date.month = endDate.getMonth();
+ }
+ }
+
+ /*
+ tm_sec int seconds after the minute 0-61*
+ tm_min int minutes after the hour 0-59
+ tm_hour int hours since midnight 0-23
+ tm_mday int day of the month 1-31
+ tm_mon int months since January 0-11
+ tm_year int years since 1900
+ tm_wday int days since Sunday 0-6
+ tm_yday int days since January 1 0-365
+ tm_isdst int Daylight Saving Time flag
+ */
+
+ var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0);
+ {{{ makeSetValue('tm', '___tm_struct_layout.tm_sec', 'fullDate.getSeconds()', 'i32') }}}
+ {{{ makeSetValue('tm', '___tm_struct_layout.tm_min', 'fullDate.getMinutes()', 'i32') }}}
+ {{{ makeSetValue('tm', '___tm_struct_layout.tm_hour', 'fullDate.getHours()', 'i32') }}}
+ {{{ makeSetValue('tm', '___tm_struct_layout.tm_mday', 'fullDate.getDate()', 'i32') }}}
+ {{{ 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_isdst', '0', 'i32') }}}
+
+ // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F
+ // TODO: not sure that intArrayFromString handles all unicode characters correctly
+ return buf+intArrayFromString(matches[0]).length-1;
+ }
+
return 0;
},
strptime_l: 'strptime', // no locale support yet
diff --git a/src/library_browser.js b/src/library_browser.js
index 822e99d6..7f79b2bd 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -91,6 +91,10 @@ mergeInto(LibraryManager.library, {
if (Browser.hasBlobConstructor) {
try {
b = new Blob([byteArray], { type: 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) });
+ }
} catch(e) {
Runtime.warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder');
}
diff --git a/src/library_gl.js b/src/library_gl.js
index e59492cf..959773bc 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -122,14 +122,6 @@ var LibraryGL = {
}
},
- // Linear lookup in one of the tables (buffers, programs, etc.). TODO: consider using a weakmap to make this faster, if it matters
- scan: function(table, object) {
- for (var item in table) {
- if (table[item] == object) return item;
- }
- return 0;
- },
-
// Find a token in a shader source string
findToken: function(source, token) {
function isIdentChar(ch) {
@@ -402,15 +394,15 @@ var LibraryGL = {
{{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}};
}
} else if (result instanceof WebGLBuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.buffers, result)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
} else if (result instanceof WebGLProgram) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.programs, result)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
} else if (result instanceof WebGLFramebuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.framebuffers, result)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
} else if (result instanceof WebGLRenderbuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.renderbuffers, result)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
} else if (result instanceof WebGLTexture) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.textures, result)', 'i32') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'i32') }}};
} else {
throw 'Unknown object returned from WebGL getParameter';
}
@@ -445,15 +437,15 @@ var LibraryGL = {
{{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}};
}
} else if (result instanceof WebGLBuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.buffers, result)', 'float') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
} else if (result instanceof WebGLProgram) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.programs, result)', 'float') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
} else if (result instanceof WebGLFramebuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.framebuffers, result)', 'float') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
} else if (result instanceof WebGLRenderbuffer) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.renderbuffers, result)', 'float') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
} else if (result instanceof WebGLTexture) {
- {{{ makeSetValue('p', '0', 'GL.scan(GL.textures, result)', 'float') }}};
+ {{{ makeSetValue('p', '0', 'result.name | 0', 'float') }}};
} else {
throw 'Unknown object returned from WebGL getParameter';
}
@@ -508,7 +500,9 @@ var LibraryGL = {
glGenTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.textures);
- GL.textures[id] = Module.ctx.createTexture();
+ var texture = Module.ctx.createTexture();
+ texture.name = id;
+ GL.textures[id] = texture;
{{{ makeSetValue('textures', 'i*4', 'id', 'i32') }}};
}
},
@@ -517,7 +511,9 @@ var LibraryGL = {
glDeleteTextures: function(n, textures) {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}};
- Module.ctx.deleteTexture(GL.textures[id]);
+ var texture = GL.textures[id];
+ Module.ctx.deleteTexture(texture);
+ texture.name = 0;
GL.textures[id] = null;
}
},
@@ -622,7 +618,9 @@ var LibraryGL = {
glGenBuffers: function(n, buffers) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.buffers);
- GL.buffers[id] = Module.ctx.createBuffer();
+ var buffer = Module.ctx.createBuffer();
+ buffer.name = id;
+ GL.buffers[id] = buffer;
{{{ makeSetValue('buffers', 'i*4', 'id', 'i32') }}};
}
},
@@ -631,7 +629,9 @@ var LibraryGL = {
glDeleteBuffers: function(n, buffers) {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}};
- Module.ctx.deleteBuffer(GL.buffers[id]);
+ var buffer = GL.buffers[id];
+ Module.ctx.deleteBuffer(buffer);
+ buffer.name = 0;
GL.buffers[id] = null;
if (id == GL.currArrayBuffer) GL.currArrayBuffer = 0;
@@ -665,7 +665,9 @@ var LibraryGL = {
glGenRenderbuffers: function(n, renderbuffers) {
for (var i = 0; i < n; i++) {
var id = GL.getNewId(GL.renderbuffers);
- GL.renderbuffers[id] = Module.ctx.createRenderbuffer();
+ var renderbuffer = Module.ctx.createRenderbuffer();
+ renderbuffer.name = id;
+ GL.renderbuffers[id] = renderbuffer;
{{{ makeSetValue('renderbuffers', 'i*4', 'id', 'i32') }}};
}
},
@@ -674,8 +676,10 @@ var LibraryGL = {
glDeleteRenderbuffers: function(n, renderbuffers) {
for (var i = 0; i < n; i++) {
var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}};
- Module.ctx.deleteRenderbuffer(GL.renderbuffers[id]);
- GL.renderbuffers[id];
+ var renderbuffer = GL.renderbuffers[id];
+ Module.ctx.deleteRenderbuffer(renderbuffer);
+ renderbuffer.name = 0;
+ GL.renderbuffers[id] = null;
}
},
@@ -1139,13 +1143,17 @@ var LibraryGL = {
glCreateProgram__sig: 'i',
glCreateProgram: function() {
var id = GL.getNewId(GL.programs);
- GL.programs[id] = Module.ctx.createProgram();
+ var program = Module.ctx.createProgram();
+ program.name = id;
+ GL.programs[id] = program;
return id;
},
glDeleteProgram__sig: 'vi',
glDeleteProgram: function(program) {
- Module.ctx.deleteProgram(GL.programs[program]);
+ var program = GL.programs[program];
+ Module.ctx.deleteProgram(program);
+ program.name = 0;
GL.programs[program] = null;
GL.uniformTable[program] = null;
},
@@ -1221,7 +1229,9 @@ var LibraryGL = {
glGenFramebuffers: function(n, ids) {
for (var i = 0; i < n; ++i) {
var id = GL.getNewId(GL.framebuffers);
- GL.framebuffers[id] = Module.ctx.createFramebuffer();
+ var framebuffer = Module.ctx.createFramebuffer();
+ framebuffer.name = id;
+ GL.framebuffers[id] = framebuffer;
{{{ makeSetValue('ids', 'i*4', 'id', 'i32') }}};
}
},
@@ -1230,7 +1240,9 @@ var LibraryGL = {
glDeleteFramebuffers: function(n, framebuffers) {
for (var i = 0; i < n; ++i) {
var id = {{{ makeGetValue('framebuffers', 'i*4', 'i32') }}};
- Module.ctx.deleteFramebuffer(GL.framebuffers[id]);
+ var framebuffer = GL.framebuffers[id];
+ Module.ctx.deleteFramebuffer(framebuffer);
+ framebuffer.name = 0;
GL.framebuffers[id] = null;
}
},
diff --git a/src/library_sdl.js b/src/library_sdl.js
index b64a34ef..b7d73862 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -21,6 +21,8 @@ var LibrarySDL = {
version: null,
surfaces: {},
+ // A pool of freed canvas elements. Reusing them avoids GC pauses.
+ canvasPool: [],
events: [],
fonts: [null],
@@ -288,7 +290,11 @@ var LibrarySDL = {
SDL.GL = SDL.GL || useWebGL;
var canvas;
if (!usePageCanvas) {
- canvas = document.createElement('canvas');
+ if (SDL.canvasPool.length > 0) {
+ canvas = SDL.canvasPool.pop();
+ } else {
+ canvas = document.createElement('canvas');
+ }
canvas.width = width;
canvas.height = height;
} else {
@@ -355,8 +361,10 @@ var LibrarySDL = {
},
freeSurface: function(surf) {
- _free(SDL.surfaces[surf].buffer);
- _free(SDL.surfaces[surf].pixelFormat);
+ var info = SDL.surfaces[surf];
+ if (!info.usePageCanvas && info.canvas) SDL.canvasPool.push(info.canvas);
+ _free(info.buffer);
+ _free(info.pixelFormat);
_free(surf);
SDL.surfaces[surf] = null;
},
diff --git a/system/include/libc/sys/dirent.h b/system/include/libc/sys/dirent.h
index 0d8b02b5..e6ce831e 100644
--- a/system/include/libc/sys/dirent.h
+++ b/system/include/libc/sys/dirent.h
@@ -24,6 +24,7 @@ DIR *opendir(const char *);
void seekdir(DIR *, long);
long telldir(DIR *);
DIR *readdir(DIR *);
+int readdir_r(DIR *, struct dirent *, struct dirent **);
int closedir(DIR *dirp);
void rewinddir(DIR *dirp);
int scandir(const char *dirp,
diff --git a/tests/dirent/test_readdir.c b/tests/dirent/test_readdir.c
new file mode 100644
index 00000000..9f7b12e8
--- /dev/null
+++ b/tests/dirent/test_readdir.c
@@ -0,0 +1,132 @@
+#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 <sys/stat.h>
+
+static 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() {
+ mkdir("nocanread", 0111);
+ mkdir("foobar", 0777);
+ create_file("foobar/file.txt", "ride into the danger zone", 0666);
+}
+
+void cleanup() {
+ rmdir("nocanread");
+ unlink("foobar/file.txt");
+ rmdir("foobar");
+}
+
+void test() {
+ int err;
+ int loc;
+ DIR *dir;
+ struct dirent *ent;
+ struct dirent ent_r;
+ struct dirent *result;
+
+ // check bad opendir input
+ dir = opendir("noexist");
+ assert(!dir);
+ assert(errno == ENOENT);
+ dir = opendir("nocanread");
+ assert(!dir);
+ assert(errno == EACCES);
+ dir = opendir("foobar/file.txt");
+ assert(!dir);
+ assert(errno == ENOTDIR);
+
+ // check bad readdir input
+ dir = opendir("foobar");
+ closedir(dir);
+ ent = readdir(dir);
+ assert(!ent);
+ assert(errno == EBADF);
+
+ // check bad readdir_r input
+ dir = opendir("foobar");
+ closedir(dir);
+ err = readdir_r(dir, NULL, &result);
+ assert(err == EBADF);
+
+ //
+ // do a normal read with readdir
+ //
+ dir = opendir("foobar");
+ assert(dir);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, "."));
+ assert(ent->d_type & DT_DIR);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, ".."));
+ assert(ent->d_type & DT_DIR);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, "file.txt"));
+ assert(ent->d_type & DT_REG);
+ ent = readdir(dir);
+ assert(!ent);
+
+ // test rewinddir
+ rewinddir(dir);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, "."));
+
+ // test seek / tell
+ rewinddir(dir);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, "."));
+ loc = telldir(dir);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, ".."));
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, "file.txt"));
+ seekdir(dir, loc);
+ ent = readdir(dir);
+ assert(!strcmp(ent->d_name, ".."));
+
+ //
+ // do a normal read with readdir_r
+ //
+ rewinddir(dir);
+ err = readdir_r(dir, &ent_r, &result);
+ assert(!err);
+ assert(&ent_r == result);
+ assert(!strcmp(ent_r.d_name, "."));
+ err = readdir_r(dir, &ent_r, &result);
+ assert(!err);
+ assert(&ent_r == result);
+ assert(!strcmp(ent_r.d_name, ".."));
+ err = readdir_r(dir, &ent_r, &result);
+ assert(!err);
+ assert(&ent_r == result);
+ assert(!strcmp(ent_r.d_name, "file.txt"));
+ err = readdir_r(dir, &ent_r, &result);
+ assert(!err);
+ assert(!result);
+
+ err = closedir(dir);
+ assert(!err);
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/fcntl-misc/src.c b/tests/fcntl-misc/src.c
index 73734969..7cdbbcd6 100644
--- a/tests/fcntl-misc/src.c
+++ b/tests/fcntl-misc/src.c
@@ -6,7 +6,7 @@
int main() {
struct stat s;
- int f = open("/test", O_RDONLY, 0777);
+ int f = open("/test", O_RDWR, 0777);
printf("posix_fadvise: %d\n", posix_fadvise(f, 3, 2, POSIX_FADV_DONTNEED));
printf("errno: %d\n", errno);
diff --git a/tests/fcntl-open/output.txt b/tests/fcntl-open/output.txt
index 314ae880..07b106ac 100644
--- a/tests/fcntl-open/output.txt
+++ b/tests/fcntl-open/output.txt
@@ -19,8 +19,8 @@ errno: 0
st_mode: 0100000
EXISTING FOLDER 0,1
-success: 0
-errno: 21
+success: 1
+errno: 0
st_mode: 040000
NON-EXISTING 0,1
@@ -139,8 +139,8 @@ errno: 0
st_mode: 0100000
EXISTING FOLDER 0,9
-success: 0
-errno: 21
+success: 1
+errno: 0
st_mode: 040000
NON-EXISTING 0,9
@@ -720,4 +720,4 @@ st_mode: 0100000
CREAT
success: 1
-errno: 0
+errno: 0 \ No newline at end of file
diff --git a/tests/fcntl-open/src.c b/tests/fcntl-open/src.c
index 52d2e7e4..bd52dd3f 100644
--- a/tests/fcntl-open/src.c
+++ b/tests/fcntl-open/src.c
@@ -1,13 +1,45 @@
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
-#include <sys/stat.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
-int main() {
+char nonexistent_name[] = "noexist-##";
+
+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("test-file", "abcdef", 0777);
+ mkdir("test-folder", 0777);
+}
+
+void cleanup() {
+ unlink("test-file");
+ rmdir("test-folder");
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 16; j++) {
+ nonexistent_name[8] = 'a' + i;
+ nonexistent_name[9] = 'a' + j;
+ unlink(nonexistent_name);
+ }
+ }
+ unlink("creat-me");
+}
+
+void test() {
struct stat s;
int modes[] = {O_RDONLY, O_WRONLY, O_RDWR};
- char nonexistent_name[] = "/noexist-##";
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 16; j++) {
@@ -18,25 +50,25 @@ int main() {
if (j & 0x8) flags |= O_APPEND;
printf("EXISTING FILE %d,%d\n", i, j);
- printf("success: %d\n", open("/test-file", flags, 0777) != -1);
+ printf("success: %d\n", open("test-file", flags, 0777) != -1);
printf("errno: %d\n", errno);
- stat("/test-file", &s);
+ stat("test-file", &s);
printf("st_mode: 0%o\n", s.st_mode & 037777777000);
memset(&s, 0, sizeof s);
printf("\n");
errno = 0;
printf("EXISTING FOLDER %d,%d\n", i, j);
- printf("success: %d\n", open("/test-folder", flags, 0777) != -1);
+ printf("success: %d\n", open("test-folder", flags, 0777) != -1);
printf("errno: %d\n", errno);
- stat("/test-folder", &s);
+ stat("test-folder", &s);
printf("st_mode: 0%o\n", s.st_mode & 037777777000);
memset(&s, 0, sizeof s);
printf("\n");
errno = 0;
- nonexistent_name[9] = 'a' + i;
- nonexistent_name[10] = 'a' + j;
+ nonexistent_name[8] = 'a' + i;
+ nonexistent_name[9] = 'a' + j;
printf("NON-EXISTING %d,%d\n", i, j);
printf("success: %d\n", open(nonexistent_name, flags, 0777) != -1);
printf("errno: %d\n", errno);
@@ -49,8 +81,14 @@ int main() {
}
printf("CREAT\n");
- printf("success: %d\n", creat("/creat-me", 0777) != -1);
+ printf("success: %d\n", creat("creat-me", 0777) != -1);
printf("errno: %d\n", errno);
-
- return 0;
}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/runner.py b/tests/runner.py
index 18d5f4d1..c08434f5 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -1981,6 +1981,18 @@ Succeeded!
self.do_run(src, "1.0 2.0 -1.0 -2.0 2.0 3.0 -2.0 -3.0 "
"1 2 -1 -2 2 2 -2 -2")
+ def test_llrint(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
+ src = r'''
+ #include <stdio.h>
+ #include <math.h>
+ int main() {
+ printf("%lld\n%lld\n%lld\n%lld\n", llrint(0.1), llrint(0.6), llrint(1.25), llrint(1099511627776.667));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0\n1\n1\n1099511627777\n')
+
def test_getgep(self):
# Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP
src = '''
@@ -4958,6 +4970,130 @@ The current type of b is: 9
'''
self.do_run(src, 'time: ') # compilation check, mainly
+
+ def test_strptime_tm(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ int main() {
+ struct tm tm;
+ char *ptr = strptime("17410105012000", "%H%M%S%d%m%Y", &tm);
+
+ printf("%s: %s, %d/%d/%d %d:%d:%d",
+ (ptr != NULL && *ptr=='\0') ? "OK" : "ERR",
+ tm.tm_wday == 0 ? "Sun" : (tm.tm_wday == 1 ? "Mon" : (tm.tm_wday == 2 ? "Tue" : (tm.tm_wday == 3 ? "Wed" : (tm.tm_wday == 4 ? "Thu" : (tm.tm_wday == 5 ? "Fri" : (tm.tm_wday == 6 ? "Sat" : "ERR")))))),
+ tm.tm_mon+1,
+ tm.tm_mday,
+ tm.tm_year+1900,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec
+ );
+ }
+ '''
+ self.do_run(src, 'OK: Wed, 1/5/2000 17:41:1')
+
+ def test_strptime_days(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ static const struct {
+ const char *input;
+ const char *format;
+ } day_tests[] = {
+ { "2000-01-01", "%Y-%m-%d"},
+ { "03/03/00", "%D"},
+ { "9/9/99", "%x"},
+ { "19990502123412", "%Y%m%d%H%M%S"},
+ { "2001 20 Mon", "%Y %U %a"},
+ { "2006 4 Fri", "%Y %U %a"},
+ { "2001 21 Mon", "%Y %W %a"},
+ { "2013 29 Wed", "%Y %W %a"},
+ { "2000-01-01 08:12:21 AM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2000-01-01 08:12:21 PM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2001 17 Tue", "%Y %U %a"},
+ { "2001 8 Thursday", "%Y %W %a"},
+ };
+
+ int main() {
+ struct tm tm;
+
+ for (int i = 0; i < sizeof (day_tests) / sizeof (day_tests[0]); ++i) {
+ memset (&tm, '\0', sizeof (tm));
+ char *ptr = strptime(day_tests[i].input, day_tests[i].format, &tm);
+
+ printf("%s: %d/%d/%d (%dth DoW, %dth DoY)\n", (ptr != NULL && *ptr=='\0') ? "OK" : "ERR", tm.tm_mon+1, tm.tm_mday, 1900+tm.tm_year, tm.tm_wday, tm.tm_yday);
+ }
+ }
+ '''
+ self.do_run(src, 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 3/3/2000 (5th DoW, 62th DoY)\n'\
+ 'OK: 9/9/1999 (4th DoW, 251th DoY)\n'\
+ 'OK: 5/2/1999 (0th DoW, 121th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 1/27/2006 (5th DoW, 26th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 7/24/2013 (3th DoW, 204th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 5/1/2001 (2th DoW, 120th DoY)\n'\
+ 'OK: 2/22/2001 (4th DoW, 52th DoY)\n'\
+ )
+
+ def test_strptime_reentrant(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ int main () {
+ int result = 0;
+ struct tm tm;
+
+ memset (&tm, 0xaa, sizeof (tm));
+
+ /* Test we don't crash on uninitialized struct tm.
+ Some fields might contain bogus values until everything
+ needed is initialized, but we shouldn't crash. */
+ if (strptime ("2007", "%Y", &tm) == NULL
+ || strptime ("12", "%d", &tm) == NULL
+ || strptime ("Feb", "%b", &tm) == NULL
+ || strptime ("13", "%M", &tm) == NULL
+ || strptime ("21", "%S", &tm) == NULL
+ || strptime ("16", "%H", &tm) == NULL) {
+ printf("ERR: returned NULL");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 1 || tm.tm_yday != 42) {
+ printf("ERR: unexpected tm content (1) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strptime ("8", "%d", &tm) == NULL) {
+ printf("ERR: strptime failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 4 || tm.tm_yday != 38) {
+ printf("ERR: unexpected tm content (2) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("OK");
+ }
+ '''
+ self.do_run(src, 'OK')
+
def test_intentional_fault(self):
# Some programs intentionally segfault themselves, we should compile that into a throw
src = r'''
@@ -6838,84 +6974,9 @@ def process(filename):
self.emcc_args += ['--embed-file', 'three_numbers.txt']
self.do_run(src, 'match = 3\nx = -1.0, y = 0.1, z = -0.1\n')
- def test_folders(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- FS.createFolder('/', 'test', true, false);
- FS.createPath('/', 'test/hello/world/', true, false);
- FS.createPath('/test', 'goodbye/world/', true, false);
- FS.createPath('/test/goodbye', 'noentry', false, false);
- FS.createDataFile('/test', 'freeforall.ext', 'abc', true, true);
- FS.createDataFile('/test', 'restricted.ext', 'def', false, false);
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
- src = r'''
- #include <stdio.h>
- #include <dirent.h>
- #include <errno.h>
-
- int main() {
- struct dirent *e;
-
- // Basic correct behaviour.
- DIR* d = opendir("/test");
- printf("--E: %d\n", errno);
- while ((e = readdir(d))) puts(e->d_name);
- printf("--E: %d\n", errno);
-
- // Empty folder; tell/seek.
- puts("****");
- d = opendir("/test/hello/world/");
- e = readdir(d);
- puts(e->d_name);
- int pos = telldir(d);
- e = readdir(d);
- puts(e->d_name);
- seekdir(d, pos);
- e = readdir(d);
- puts(e->d_name);
-
- // Errors.
- puts("****");
- printf("--E: %d\n", errno);
- d = opendir("/test/goodbye/noentry");
- printf("--E: %d, D: %d\n", errno, d);
- d = opendir("/i/dont/exist");
- printf("--E: %d, D: %d\n", errno, d);
- d = opendir("/test/freeforall.ext");
- printf("--E: %d, D: %d\n", errno, d);
- while ((e = readdir(d))) puts(e->d_name);
- printf("--E: %d\n", errno);
-
- return 0;
- }
- '''
- expected = '''
- --E: 0
- .
- ..
- hello
- goodbye
- freeforall.ext
- restricted.ext
- --E: 0
- ****
- .
- ..
- ..
- ****
- --E: 0
- --E: 13, D: 0
- --E: 2, D: 0
- --E: 20, D: 0
- --E: 9
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run)
+ def test_readdir(self):
+ src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
def test_stat(self):
add_pre_run = '''
@@ -6950,20 +7011,9 @@ def process(filename):
self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
def test_fcntl_open(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- FS.createDataFile('/', 'test-file', 'abcdef', true, true);
- FS.createFolder('/', 'test-folder', true, true);
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
src = open(path_from_root('tests', 'fcntl-open', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'fcntl-open', 'output.txt'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run, extra_emscripten_args=['-H', 'libc/fcntl.h'])
+ self.do_run(src, expected, force_c=True, extra_emscripten_args=['-H', 'libc/fcntl.h'])
def test_fcntl_misc(self):
add_pre_run = '''
@@ -7131,49 +7181,8 @@ def process(filename):
self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected))
def test_utime(self):
- add_pre_run_and_checks = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- \'\'\'
- var TEST_F1 = FS.createFolder('/', 'writeable', true, true);
- var TEST_F2 = FS.createFolder('/', 'unwriteable', true, false);
- \'\'\'
- ).replace(
- '// {{POST_RUN_ADDITIONS}}',
- \'\'\'
- Module.print('first changed: ' + (TEST_F1.timestamp == 1200000000000));
- Module.print('second changed: ' + (TEST_F2.timestamp == 1200000000000));
- \'\'\'
- )
- open(filename, 'w').write(src)
-'''
- src = r'''
- #include <stdio.h>
- #include <errno.h>
- #include <utime.h>
-
- int main() {
- struct utimbuf t = {1000000000, 1200000000};
- char* writeable = "/writeable";
- char* unwriteable = "/unwriteable";
-
- utime(writeable, &t);
- printf("writeable errno: %d\n", errno);
-
- utime(unwriteable, &t);
- printf("unwriteable errno: %d\n", errno);
-
- return 0;
- }
- '''
- expected = '''
- writeable errno: 0
- unwriteable errno: 1
- first changed: true
- second changed: false
- '''
- self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run_and_checks)
+ src = open(path_from_root('tests', 'utime', 'test_utime.c'), 'r').read()
+ self.do_run(src, 'success', force_c=True)
def test_utf(self):
self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well
@@ -7265,38 +7274,6 @@ def process(filename):
Settings.LINKABLE = linkable # regression check for issue #273
self.do_run(src, "1 2 3")
- def test_readdir(self):
- add_pre_run = '''
-def process(filename):
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- "FS.createFolder('', 'test', true, true);\\nFS.createLazyFile( 'test', 'some_file', 'http://localhost/some_file', true, false);\\nFS.createFolder('test', 'some_directory', true, true);"
- )
- open(filename, 'w').write(src)
-'''
-
- src = '''
- #include <dirent.h>
- #include <stdio.h>
-
- int main()
- {
- DIR * dir;
- dirent * entity;
-
- dir = opendir( "test" );
-
- while( ( entity = readdir( dir ) ) )
- {
- printf( "%s is a %s\\n", entity->d_name, entity->d_type & DT_DIR ? "directory" : "file" );
- }
-
- return 0;
- }
-
- '''
- self.do_run(src, ". is a directory\n.. is a directory\nsome_file is a file\nsome_directory is a directory", post_build=add_pre_run)
-
def test_fs_base(self):
Settings.INCLUDE_FULL_LIBRARY = 1
try:
@@ -7353,18 +7330,8 @@ def process(filename):
self.do_run(src, expected, extra_emscripten_args=['-H', 'libc/unistd.h'])
def test_unistd_ttyname(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'ttyname.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
src = open(path_from_root('tests', 'unistd', 'ttyname.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'ttyname.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
+ self.do_run(src, 'success', force_c=True)
def test_unistd_dup(self):
src = open(path_from_root('tests', 'unistd', 'dup.c'), 'r').read()
@@ -7396,18 +7363,8 @@ def process(filename):
self.do_run(src, expected)
def test_unistd_isatty(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'isatty.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
src = open(path_from_root('tests', 'unistd', 'isatty.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'isatty.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
+ self.do_run(src, 'success', force_c=True)
def test_unistd_sysconf(self):
src = open(path_from_root('tests', 'unistd', 'sysconf.c'), 'r').read()
diff --git a/tests/unistd/isatty.c b/tests/unistd/isatty.c
index cc1ff641..191036e9 100644
--- a/tests/unistd/isatty.c
+++ b/tests/unistd/isatty.c
@@ -1,28 +1,28 @@
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
int main() {
- printf("read: %d\n", isatty(open("/read", O_RDONLY)));
- printf("errno: %d\n", errno);
- errno = 0;
+ int err;
+
+ err = isatty(-1);
+ assert(!err);
+ assert(errno == EBADF);
- printf("write: %d\n", isatty(open("/write", O_WRONLY)));
- printf("errno: %d\n", errno);
- errno = 0;
+ err = isatty(open("/dev/stdin", O_RDONLY));
+ assert(err == 1);
- printf("all: %d\n", isatty(open("/all", O_RDONLY)));
- printf("errno: %d\n", errno);
- errno = 0;
+ err = isatty(open("/dev/null", O_RDONLY));
+ assert(!err);
- printf("folder: %d\n", isatty(open("/folder", O_RDONLY)));
- printf("errno: %d\n", errno);
- errno = 0;
+ err = isatty(open("/dev", O_RDONLY));
+ assert(!err);
- printf("file: %d\n", isatty(open("/file", O_RDONLY)));
- printf("errno: %d\n", errno);
- errno = 0;
+ puts("success");
- return 0;
-}
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/unistd/isatty.js b/tests/unistd/isatty.js
deleted file mode 100644
index d88bd2be..00000000
--- a/tests/unistd/isatty.js
+++ /dev/null
@@ -1,5 +0,0 @@
-FS.createDevice('/', 'read', function() {}, null);
-FS.createDevice('/', 'write', null, function() {});
-FS.createDevice('/', 'all', function() {}, function() {});
-FS.createFolder('/', 'folder', true, true);
-FS.createDataFile('/', 'file', 'test', true, true);
diff --git a/tests/unistd/isatty.out b/tests/unistd/isatty.out
deleted file mode 100644
index 6823c1f0..00000000
--- a/tests/unistd/isatty.out
+++ /dev/null
@@ -1,10 +0,0 @@
-read: 0
-errno: 25
-write: 0
-errno: 25
-all: 0
-errno: 25
-folder: 0
-errno: 25
-file: 0
-errno: 25
diff --git a/tests/unistd/ttyname.c b/tests/unistd/ttyname.c
index 7080be5d..b7cc27bd 100644
--- a/tests/unistd/ttyname.c
+++ b/tests/unistd/ttyname.c
@@ -1,51 +1,43 @@
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
int main() {
+ int err;
+ int stdin, null, dev;
char buffer[256];
- int d = open("/device", O_RDWR);
- int f = open("/", O_RDONLY);
char* result;
+ stdin = open("/dev/stdin", O_RDONLY);
+ null = open("/dev/null", O_RDONLY);
+ dev = open("/dev", O_RDONLY);
+
result = ctermid(buffer);
- if (result) {
- printf("ctermid: %s\n", result);
- } else {
- printf("ctermid errno: %d\n", errno);
- errno = 0;
- }
-
- if (ttyname_r(d, buffer, 256) == 0) {
- printf("ttyname_r(d, ..., 256): %s\n", buffer);
- } else {
- printf("ttyname_r(d, ..., 256) errno: %d\n", errno);
- errno = 0;
- }
-
- if (ttyname_r(d, buffer, 2) == 0) {
- printf("ttyname_r(d, ..., 2): %s\n", buffer);
- } else {
- printf("ttyname_r(d, ..., 2) errno: %d\n", errno);
- errno = 0;
- }
-
- result = ttyname(d);
- if (result) {
- printf("ttyname(d): %s\n", result);
- } else {
- printf("ttyname(d) errno: %d\n", errno);
- errno = 0;
- }
-
- result = ttyname(f);
- if (result) {
- printf("ttyname(f): %s\n", result);
- } else {
- printf("ttyname(f) errno: %d\n", errno);
- errno = 0;
- }
-
- return 0;
+ assert(!strcmp(result, "/dev/tty"));
+
+ // strstr instead of strcmp as native code may
+ // be using a virtual console (e.g. /dev/tty02)
+ err = ttyname_r(stdin, buffer, 256);
+ assert(!err);
+ assert(strstr(buffer, "/dev/tty"));
+
+ err = ttyname_r(stdin, buffer, 2);
+ assert(err == ERANGE);
+
+ result = ttyname(stdin);
+ assert(strstr(result, "/dev/tty"));
+
+ result = ttyname(null);
+ assert(!result);
+
+ result = ttyname(dev);
+ assert(!result);
+
+ puts("success");
+
+ return EXIT_SUCCESS;
}
diff --git a/tests/unistd/ttyname.js b/tests/unistd/ttyname.js
deleted file mode 100644
index a21f417f..00000000
--- a/tests/unistd/ttyname.js
+++ /dev/null
@@ -1 +0,0 @@
-FS.createDevice('/', 'device', function() {}, function() {});
diff --git a/tests/unistd/ttyname.out b/tests/unistd/ttyname.out
deleted file mode 100644
index b47cbf75..00000000
--- a/tests/unistd/ttyname.out
+++ /dev/null
@@ -1,5 +0,0 @@
-ctermid: /dev/tty
-ttyname_r(d, ..., 256): /device
-ttyname_r(d, ..., 2) errno: 34
-ttyname(d): /device
-ttyname(f) errno: 25
diff --git a/tests/utime/test_utime.c b/tests/utime/test_utime.c
new file mode 100644
index 00000000..1793f4a5
--- /dev/null
+++ b/tests/utime/test_utime.c
@@ -0,0 +1,53 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/stat.h>
+
+void setup() {
+ mkdir("writeable", 0777);
+ mkdir("unwriteable", 0111);
+}
+
+void cleanup() {
+ rmdir("writeable");
+ rmdir("unwriteable");
+}
+
+void test() {
+ struct stat s;
+ // currently, the most recent timestamp is shared for atime,
+ // ctime and mtime. using unique values for each in the test
+ // will fail
+ struct utimbuf t = {1000000000, 1000000000};
+
+ utime("writeable", &t);
+ assert(!errno);
+ memset(&s, 0, sizeof s);
+ stat("writeable", &s);
+ assert(s.st_atime == t.actime);
+ assert(s.st_mtime == t.modtime);
+
+ // write permissions aren't checked when setting node
+ // attributes unless the user uid isn't the owner (so
+ // therefor, this should work fine)
+ utime("unwriteable", &t);
+ assert(!errno);
+ memset(&s, 0, sizeof s);
+ stat("unwriteable", &s);
+ assert(s.st_atime == t.actime);
+ assert(s.st_mtime == t.modtime);
+
+ puts("success");
+}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 6987511c..71a59921 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -562,7 +562,8 @@ function simplifyExpressionsPre(ast) {
} else if (type === 'binary' && node[1] === '^') {
// LLVM represents bitwise not as xor with -1. Translate it back to an actual bitwise not.
if (node[3][0] === 'unary-prefix' && node[3][1] === '-' && node[3][2][0] === 'num' &&
- node[3][2][1] === 1) {
+ node[3][2][1] === 1 &&
+ !(node[2][0] == 'unary-prefix' && node[2][1] == '~')) { // avoid creating ~~~ which is confusing for asm given the role of ~~
return ['unary-prefix', '~', node[2]];
}
} else if (type === 'binary' && node[1] === '>>' && node[3][0] === 'num' &&
@@ -636,7 +637,8 @@ function simplifyExpressionsPre(ast) {
if (node[0] === 'seq' && node[1][0] === 'assign' && node[1][2][0] === 'sub' && node[1][2][1][0] === 'name' &&
(node[1][2][1][1] === 'HEAP32' || node[1][2][1][1] === 'HEAPF32') &&
node[1][2][2][0] === 'binary' && node[1][2][2][2][0] === 'name' && node[1][2][2][2][1] === 'tempDoublePtr' &&
- node[1][3][0] === 'sub' && node[1][3][1][0] === 'name' && (node[1][3][1][1] === 'HEAP32' || node[1][3][1][1] === 'HEAPF32')) {
+ node[1][3][0] === 'sub' && node[1][3][1][0] === 'name' && (node[1][3][1][1] === 'HEAP32' || node[1][3][1][1] === 'HEAPF32') &&
+ node[2][0] !== 'seq') { // avoid (x, y, z) which can be used for tempDoublePtr on doubles for alignment fixes
if (node[1][2][1][1] === 'HEAP32') {
node[1][3][1][1] = 'HEAPF32';
return ['unary-prefix', '+', node[1][3]];
diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py
index a4e1ca6c..4e7d5474 100644
--- a/tools/js_optimizer.py
+++ b/tools/js_optimizer.py
@@ -102,16 +102,20 @@ start_asm_marker = '// EMSCRIPTEN_START_ASM\n'
end_asm_marker = '// EMSCRIPTEN_END_ASM\n'
def run_on_chunk(command):
- filename = command[2] # XXX hackish
- #print >> sys.stderr, 'running js optimizer command', ' '.join(command), '""""', open(filename).read()
- output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
- assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output
- filename = temp_files.get(os.path.basename(filename) + '.jo.js').name
- f = open(filename, 'w')
- f.write(output)
- f.close()
- if DEBUG and not shared.WINDOWS: print >> sys.stderr, '.' # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console.
- return filename
+ try:
+ filename = command[2] # XXX hackish
+ #print >> sys.stderr, 'running js optimizer command', ' '.join(command), '""""', open(filename).read()
+ output = subprocess.Popen(command, stdout=subprocess.PIPE).communicate()[0]
+ assert len(output) > 0 and not output.startswith('Assertion failed'), 'Error in js optimizer: ' + output
+ filename = temp_files.get(os.path.basename(filename) + '.jo.js').name
+ f = open(filename, 'w')
+ f.write(output)
+ f.close()
+ if DEBUG and not shared.WINDOWS: print >> sys.stderr, '.' # Skip debug progress indicator on Windows, since it doesn't buffer well with multiple threads printing to console.
+ return filename
+ except KeyboardInterrupt:
+ # avoid throwing keyboard interrupts from a child process
+ raise Exception()
def run_on_js(filename, passes, js_engine, jcache, source_map=False, extra_info=None):
if isinstance(jcache, bool) and jcache: jcache = shared.JCache
diff --git a/tools/shared.py b/tools/shared.py
index 0351a736..007c2ee8 100644
--- a/tools/shared.py
+++ b/tools/shared.py
@@ -726,7 +726,7 @@ class Building:
env['HOST_CXXFLAGS'] = "-W" #if set to nothing, CXXFLAGS is used, which we don't want
env['PKG_CONFIG_LIBDIR'] = path_from_root('system', 'local', 'lib', 'pkgconfig') + os.path.pathsep + path_from_root('system', 'lib', 'pkgconfig')
env['PKG_CONFIG_PATH'] = os.environ.get ('EM_PKG_CONFIG_PATH') or ''
- env['EMSCRIPTEN'] = '1'
+ env['EMSCRIPTEN'] = path_from_root()
return env
@staticmethod
diff --git a/tools/test-js-optimizer-asm-pre-output.js b/tools/test-js-optimizer-asm-pre-output.js
index b7afab26..8a5803d6 100644
--- a/tools/test-js-optimizer-asm-pre-output.js
+++ b/tools/test-js-optimizer-asm-pre-output.js
@@ -66,6 +66,7 @@ function b($this, $__n) {
HEAP32[$4] = ~HEAP32[$5];
HEAP32[$4] = ~HEAP32[$5];
HEAP32[$4] = ~HEAP32[$5];
+ h(~~g ^ -1);
return;
}
function rett() {
@@ -156,6 +157,8 @@ function tempDoublePtr($45, $14, $28, $42) {
unelim2 = 127 + $14 | 0;
func();
HEAP32[4] = unelim2;
+ barrier();
+ $f163 = (HEAP32[tempDoublePtr >> 2] = HEAP32[$f165 >> 2], HEAP32[tempDoublePtr + 4 >> 2] = HEAP32[$f165 + 4 >> 2], +HEAPF64[tempDoublePtr >> 3]);
}
function boxx($this, $aabb, $xf, $childIndex) {
$this = $this | 0;
diff --git a/tools/test-js-optimizer-asm-pre.js b/tools/test-js-optimizer-asm-pre.js
index b762a60e..5c004342 100644
--- a/tools/test-js-optimizer-asm-pre.js
+++ b/tools/test-js-optimizer-asm-pre.js
@@ -70,6 +70,7 @@ function b($this, $__n) {
HEAP32[$4] = HEAP32[$5]^-1;
// Rewrite to ~ and eliminate the |0.
HEAP32[$4] = ((HEAP32[$5]|0)^-1)|0;
+ h((~~g) ^ -1); // do NOT convert this, as it would lead to ~~~ which is confusing in asm, given the role of ~~
return;
}
function rett() {
@@ -166,6 +167,8 @@ function tempDoublePtr($45, $14, $28, $42) {
unelim2 = (HEAP32[tempDoublePtr >> 2] = 127 + $14, +HEAPF32[tempDoublePtr >> 2]);
func();
HEAPF32[4] = unelim2;
+ barrier();
+ $f163 = (HEAP32[tempDoublePtr >> 2] = HEAP32[$f165 >> 2], HEAP32[tempDoublePtr + 4 >> 2] = HEAP32[$f165 + 4 >> 2], +HEAPF64[tempDoublePtr >> 3]);
}
function boxx($this, $aabb, $xf, $childIndex) {
$this = $this | 0;