summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jsifier.js3
-rw-r--r--src/library.js341
-rw-r--r--src/library_browser.js9
-rw-r--r--src/library_gl.js229
-rw-r--r--src/library_glew.js135
-rw-r--r--src/library_sdl.js40
-rw-r--r--src/modules.js2
-rw-r--r--src/parseTools.js68
-rw-r--r--src/postamble.js5
-rw-r--r--src/preamble.js36
-rw-r--r--src/relooper/Relooper.cpp87
-rw-r--r--src/relooper/Relooper.h11
-rw-r--r--src/relooper/fuzzer.py14
-rw-r--r--src/relooper/test.cpp28
-rw-r--r--src/relooper/test.txt49
-rw-r--r--src/runtime.js2
-rw-r--r--src/shell.js12
17 files changed, 731 insertions, 340 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index a503e90d..726a5eda 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -215,6 +215,9 @@ function JSify(data, functionsOnly) {
function parseConst(value, type, ident) {
var constant = makeConst(value, type);
+ // Sadly, we've thrown away type information in makeConst, so we're not
+ // passing correct type info to parseNumerical which works around this
+ // lack.
constant = flatten(constant).map(function(x) { return parseNumerical(x) })
return constant;
}
diff --git a/src/library.js b/src/library.js
index 354e5549..d2adbf24 100644
--- a/src/library.js
+++ b/src/library.js
@@ -100,7 +100,7 @@ LibraryManager.library = {
return FS.handleFSError(e);
}
if (stream.position < 0 || stream.position >= entries.length) {
- {{{ makeSetValue('result', '0', '0', 'i8*') }}}
+ {{{ makeSetValue('result', '0', '0', 'i8*') }}};
return 0;
}
var id;
@@ -118,15 +118,15 @@ LibraryManager.library = {
FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link.
8; // DT_REG, regular file.
}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}}
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_ino, 'id', 'i32') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_off, 'offset', 'i32') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_reclen, 'name.length + 1', 'i32') }}};
for (var i = 0; i < name.length; i++) {
- {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', 'name.charCodeAt(i)', 'i8') }}};
}
- {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}}
- {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}
- {{{ makeSetValue('result', '0', 'entry', 'i8*') }}}
+ {{{ makeSetValue('entry + ' + C_STRUCTS.dirent.d_name, 'i', '0', 'i8') }}};
+ {{{ makeSetValue('entry', C_STRUCTS.dirent.d_type, 'type', 'i8') }}};
+ {{{ makeSetValue('result', '0', 'entry', 'i8*') }}};
stream.position++;
return 0;
},
@@ -149,8 +149,6 @@ LibraryManager.library = {
}
return {{{ makeGetValue(0, '_readdir.result', 'i8*') }}};
},
- __01readdir64_: 'readdir',
- // TODO: Check if we need to link any other aliases.
// ==========================================================================
// utime.h
@@ -207,13 +205,13 @@ LibraryManager.library = {
var length = i;
if (allSlashes) {
// All slashes result in a single slash.
- {{{ makeSetValue('path', '1', '0', 'i8') }}}
+ {{{ makeSetValue('path', '1', '0', 'i8') }}};
return [path, -1];
} else {
// Strip trailing slashes.
while (slashPositions.length &&
slashPositions[slashPositions.length - 1] == length - 1) {
- {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}}
+ {{{ makeSetValue('path', 'slashPositions.pop(i)', '0', 'i8') }}};
length--;
}
return [path, slashPositions.pop()];
@@ -234,9 +232,9 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/007908799/xsh/dirname.html
var result = ___libgenSplitName(path);
if (result[1] == 0) {
- {{{ makeSetValue('result[0]', 1, '0', 'i8') }}}
+ {{{ makeSetValue('result[0]', 1, '0', 'i8') }}};
} else if (result[1] !== -1) {
- {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}}
+ {{{ makeSetValue('result[0]', 'result[1]', '0', 'i8') }}};
}
return result[0];
},
@@ -257,22 +255,22 @@ LibraryManager.library = {
{{{ makeSetValue('buf', C_STRUCTS.stat.st_dev, 'stat.dev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_dev_padding, '0', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_ino_truncated, 'stat.ino', 'i32') }}};
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mode, 'stat.mode', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_nlink, 'stat.nlink', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_uid, 'stat.uid', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_gid, 'stat.gid', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_rdev, 'stat.rdev', 'i32') }}};
{{{ makeSetValue('buf', C_STRUCTS.stat.__st_rdev_padding, '0', 'i32') }}};
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_size, 'stat.size', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blksize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_blocks, 'stat.blocks', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_sec, 'Math.floor(stat.atime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_atim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_sec, 'Math.floor(stat.mtime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_mtim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_sec, 'Math.floor(stat.ctime.getTime() / 1000)', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ctim.tv_nsec, '0', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i32') }}};
return 0;
} catch (e) {
FS.handleFSError(e);
@@ -398,11 +396,6 @@ LibraryManager.library = {
stat64: 'stat',
fstat64: 'fstat',
lstat64: 'lstat',
- __01fstat64_: 'fstat',
- __01stat64_: 'stat',
- __01lstat64_: 'lstat',
-
- // TODO: Check if other aliases are needed.
// ==========================================================================
// sys/statvfs.h
@@ -414,17 +407,17 @@ LibraryManager.library = {
// int statvfs(const char *restrict path, struct statvfs *restrict buf);
// NOTE: None of the constants here are true. We're just returning safe and
// sane values.
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}}
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}} // ST_NOSUID
- {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}}
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bsize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_frsize, '4096', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_blocks, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bfree, '500000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_bavail, '500000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_files, 'FS.nextInode', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_ffree, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_favail, '1000000', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_fsid, '42', 'i32') }}};
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_flag, '2', 'i32') }}}; // ST_NOSUID
+ {{{ makeSetValue('buf', C_STRUCTS.statvfs.f_namemax, '255', 'i32') }}};
return 0;
},
fstatvfs__deps: ['statvfs'],
@@ -433,8 +426,6 @@ LibraryManager.library = {
// http://pubs.opengroup.org/onlinepubs/009604499/functions/statvfs.html
return _statvfs(0, buf);
},
- __01statvfs64_: 'statvfs',
- __01fstatvfs64_: 'fstatvfs',
// ==========================================================================
// fcntl.h
@@ -515,7 +506,7 @@ LibraryManager.library = {
var arg = {{{ makeGetValue('varargs', 0, 'i32') }}};
var offset = {{{ C_STRUCTS.flock.l_type }}};
// We're always unlocked.
- {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}
+ {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}};
return 0;
case {{{ cDefine('F_SETLK') }}}:
case {{{ cDefine('F_SETLKW') }}}:
@@ -594,7 +585,7 @@ LibraryManager.library = {
}
mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}};
if (mask) nonzero++;
- {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}
+ {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}};
}
return nonzero;
},
@@ -1174,7 +1165,7 @@ LibraryManager.library = {
} else {
var length = Math.min(len, value.length);
for (var i = 0; i < length; i++) {
- {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('buf', 'i', 'value.charCodeAt(i)', 'i8') }}};
}
if (len > length) {{{ makeSetValue('buf', 'i++', '0', 'i8') }}}
return i;
@@ -1223,9 +1214,9 @@ LibraryManager.library = {
// int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
// http://linux.die.net/man/2/getresuid
// We have just one process/group/user, all with ID 0.
- {{{ makeSetValue('ruid', '0', '0', 'i32') }}}
- {{{ makeSetValue('euid', '0', '0', 'i32') }}}
- {{{ makeSetValue('suid', '0', '0', 'i32') }}}
+ {{{ makeSetValue('ruid', '0', '0', 'i32') }}};
+ {{{ makeSetValue('euid', '0', '0', 'i32') }}};
+ {{{ makeSetValue('suid', '0', '0', 'i32') }}};
return 0;
},
getresgid: 'getresuid',
@@ -1237,7 +1228,7 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
} else {
- {{{ makeSetValue('grouplist', '0', '0', 'i32') }}}
+ {{{ makeSetValue('grouplist', '0', '0', 'i32') }}};
return 1;
}
},
@@ -1270,10 +1261,10 @@ LibraryManager.library = {
}
var length = Math.min(namelen, host.length);
for (var i = 0; i < length; i++) {
- {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('name', 'i', 'host.charCodeAt(i)', 'i8') }}};
}
if (namelen > length) {
- {{{ makeSetValue('name', 'i', '0', 'i8') }}}
+ {{{ makeSetValue('name', 'i', '0', 'i8') }}};
return 0;
} else {
___setErrNo(ERRNO_CODES.ENAMETOOLONG);
@@ -1390,8 +1381,8 @@ LibraryManager.library = {
for (var i = 0; i < nbytes; i += 2) {
var first = {{{ makeGetValue('src', 'i', 'i8') }}};
var second = {{{ makeGetValue('src', 'i + 1', 'i8') }}};
- {{{ makeSetValue('dest', 'i', 'second', 'i8') }}}
- {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}}
+ {{{ makeSetValue('dest', 'i', 'second', 'i8') }}};
+ {{{ makeSetValue('dest', 'i + 1', 'first', 'i8') }}};
}
},
tcgetpgrp: function(fildes) {
@@ -1568,11 +1559,6 @@ LibraryManager.library = {
open64: 'open',
lseek64: 'lseek',
ftruncate64: 'ftruncate',
- __01open64_: 'open',
- __01lseek64_: 'lseek',
- __01truncate64_: 'truncate',
- __01ftruncate64_: 'ftruncate',
- // TODO: Check if any other aliases are needed.
// ==========================================================================
// stdio.h
@@ -1804,7 +1790,7 @@ LibraryManager.library = {
break;
case 'X':
case 'x':
- {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}};
break;
case 'F':
case 'f':
@@ -1815,15 +1801,15 @@ LibraryManager.library = {
case 'E':
// fallthrough intended
if (long_) {
- {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}};
} else {
- {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}}
+ {{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'float') }}};
}
break;
case 's':
var array = intArrayFromString(text);
for (var j = 0; j < array.length; j++) {
- {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}}
+ {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}};
}
break;
}
@@ -1950,9 +1936,9 @@ LibraryManager.library = {
}
// Handle precision.
- var precisionSet = false;
+ var precisionSet = false, precision = -1;
if (next == {{{ charCode('.') }}}) {
- var precision = 0;
+ precision = 0;
precisionSet = true;
textIndex++;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
@@ -1969,8 +1955,10 @@ LibraryManager.library = {
}
}
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
- } else {
- var precision = 6; // Standard default.
+ }
+ if (precision === -1) {
+ precision = 6; // Standard default.
+ precisionSet = false;
}
// Handle integer sizes. WARNING: These assume a 32-bit architecture!
@@ -2257,7 +2245,7 @@ LibraryManager.library = {
case 'n': {
// Write the length written so far to the next parameter.
var ptr = getNextArg('i32*');
- {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}}
+ {{{ makeSetValue('ptr', '0', 'ret.length', 'i32') }}};
break;
}
case '%': {
@@ -2384,9 +2372,9 @@ LibraryManager.library = {
___setErrNo(ERRNO_CODES.ESPIPE);
return -1;
}
- {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}}
+ {{{ makeSetValue('pos', '0', 'stream.position', 'i32') }}};
var state = (stream.eof ? 1 : 0) + (stream.error ? 2 : 0);
- {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}}
+ {{{ makeSetValue('pos', Runtime.getNativeTypeSize('i32'), 'state', 'i32') }}};
return 0;
},
fgets__deps: ['fgetc'],
@@ -2403,9 +2391,9 @@ LibraryManager.library = {
if (streamObj.error || (streamObj.eof && i == 0)) return 0;
else if (streamObj.eof) break;
}
- {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}}
+ {{{ makeSetValue('s', 'i', 'byte_', 'i8') }}};
}
- {{{ makeSetValue('s', 'i', '0', 'i8') }}}
+ {{{ makeSetValue('s', 'i', '0', 'i8') }}};
return s;
},
gets__deps: ['fgets'],
@@ -2469,7 +2457,7 @@ LibraryManager.library = {
// int fputc(int c, FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/fputc.html
var chr = unSign(c & 0xFF);
- {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}}
+ {{{ makeSetValue('_fputc.ret', '0', 'chr', 'i8') }}};
var ret = _write(stream, _fputc.ret, 1);
if (ret == -1) {
var streamObj = FS.getStream(stream);
@@ -2523,7 +2511,7 @@ LibraryManager.library = {
return 0;
}
while (streamObj.ungotten.length && bytesToRead > 0) {
- {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}}
+ {{{ makeSetValue('ptr++', '0', 'streamObj.ungotten.pop()', 'i8') }}};
bytesToRead--;
bytesRead++;
}
@@ -2896,11 +2884,6 @@ LibraryManager.library = {
#endif
fopen64: 'fopen',
- __01fopen64_: 'fopen',
- __01freopen64_: 'freopen',
- __01fseeko64_: 'fseek',
- __01ftello64_: 'ftell',
- __01tmpfile64_: 'tmpfile',
__isoc99_fscanf: 'fscanf',
// TODO: Check if any other aliases are needed.
_IO_getc: 'getc',
@@ -2948,7 +2931,6 @@ LibraryManager.library = {
_mmap.mappings[ptr] = { malloc: ptr, num: num, allocated: allocated };
return ptr;
},
- __01mmap64_: 'mmap',
munmap: function(start, num) {
if (!_mmap.mappings) _mmap.mappings = {};
@@ -3145,7 +3127,7 @@ LibraryManager.library = {
// Set end pointer.
if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
+ {{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
// Unsign if needed.
@@ -3231,7 +3213,7 @@ LibraryManager.library = {
// Set end pointer.
if (endptr) {
- {{{ makeSetValue('endptr', 0, 'str', '*') }}}
+ {{{ makeSetValue('endptr', 0, 'str', '*') }}};
}
try {
@@ -3325,7 +3307,7 @@ LibraryManager.library = {
poolPtr = allocate(TOTAL_ENV_SIZE, 'i8', ALLOC_STATIC);
envPtr = allocate(MAX_ENV_VALUES * {{{ Runtime.QUANTUM_SIZE }}},
'i8*', ALLOC_STATIC);
- {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}}
+ {{{ makeSetValue('envPtr', '0', 'poolPtr', 'i8*') }}};
{{{ makeSetValue(makeGlobalUse('_environ'), 0, 'envPtr', 'i8*') }}};
} else {
envPtr = {{{ makeGetValue(makeGlobalUse('_environ'), '0', 'i8**') }}};
@@ -3449,7 +3431,7 @@ LibraryManager.library = {
var limit = Math.min(nelem, 3);
var doubleSize = {{{ Runtime.getNativeTypeSize('double') }}};
for (var i = 0; i < limit; i++) {
- {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}
+ {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}};
}
return limit;
},
@@ -3478,9 +3460,9 @@ LibraryManager.library = {
} else {
var size = Math.min(4095, absolute.path.length); // PATH_MAX - 1.
for (var i = 0; i < size; i++) {
- {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}}
+ {{{ makeSetValue('resolved_name', 'i', 'absolute.path.charCodeAt(i)', 'i8') }}};
}
- {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}}
+ {{{ makeSetValue('resolved_name', 'size', '0', 'i8') }}};
return resolved_name;
}
},
@@ -3688,7 +3670,7 @@ LibraryManager.library = {
var padding = 0, curr = 0, i = 0;
while ((i|0) < (num|0)) {
curr = padding ? 0 : {{{ makeGetValueAsm('psrc', 'i', 'i8') }}};
- {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}}
+ {{{ makeSetValue('pdest', 'i', 'curr', 'i8') }}};
padding = padding ? 1 : ({{{ makeGetValueAsm('psrc', 'i', 'i8') }}} == 0);
i = (i+1)|0;
}
@@ -3741,7 +3723,7 @@ LibraryManager.library = {
if ({{{ makeGetValue('pdest', 'len+i', 'i8') }}} == 0) break;
i ++;
if (i == num) {
- {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}}
+ {{{ makeSetValue('pdest', 'len+i', 0, 'i8') }}};
break;
}
}
@@ -3828,6 +3810,7 @@ LibraryManager.library = {
},
strnlen: function(ptr, num) {
+ num = num >>> 0;
for (var i = 0; i < num; i++) {
if ({{{ makeGetValue('ptr', 0, 'i8') }}} == 0) return i;
ptr++;
@@ -4108,7 +4091,7 @@ LibraryManager.library = {
var i16size = {{{ Runtime.getNativeTypeSize('i16') }}};
var arr = _malloc(values.length * i16size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}}
+ {{{ makeSetValue('arr', 'i * i16size', 'values[i]', 'i16') }}};
}
me.ret = allocate([arr + 128 * i16size], 'i16*', ALLOC_NORMAL);
}
@@ -4136,7 +4119,7 @@ LibraryManager.library = {
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
+ {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
@@ -4163,7 +4146,7 @@ LibraryManager.library = {
var i32size = {{{ Runtime.getNativeTypeSize('i32') }}};
var arr = _malloc(values.length * i32size);
for (var i = 0; i < values.length; i++) {
- {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}}
+ {{{ makeSetValue('arr', 'i * i32size', 'values[i]', 'i32') }}};
}
me.ret = allocate([arr + 128 * i32size], 'i32*', ALLOC_NORMAL);
}
@@ -4365,9 +4348,9 @@ LibraryManager.library = {
#if EXCEPTION_DEBUG
Module.printErr('Compiled code throwing an exception, ' + [ptr,type,destructor] + ', at ' + stackTrace());
#endif
- {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}}
- {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}}
- {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', '0', 'ptr', 'void*') }}};
+ {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, 'type', 'void*') }}};
+ {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'destructor', 'void*') }}};
if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
__ZSt18uncaught_exceptionv.uncaught_exception = 1;
} else {
@@ -4413,18 +4396,18 @@ LibraryManager.library = {
__THREW__ = 0;
#endif
// Clear type.
- {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', QUANTUM_SIZE, '0', 'void*') }}};
// Call destructor if one is registered then clear it.
var ptr = {{{ makeGetValue('_llvm_eh_exception.buf', '0', 'void*') }}};
var destructor = {{{ makeGetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, 'void*') }}};
if (destructor) {
Runtime.dynCall('vi', destructor, [ptr]);
- {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', 2 * QUANTUM_SIZE, '0', 'i32') }}};
}
// Free ptr if it isn't null.
if (ptr) {
___cxa_free_exception(ptr);
- {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}}
+ {{{ makeSetValue('_llvm_eh_exception.buf', '0', '0', 'void*') }}};
}
},
__cxa_get_exception_ptr__deps: ['llvm_eh_exception'],
@@ -4455,6 +4438,7 @@ LibraryManager.library = {
terminate: '__cxa_call_unexpected',
+ __gxx_personality_v0__deps: ['llvm_eh_exception', '_ZSt18uncaught_exceptionv', '__cxa_find_matching_catch'],
__gxx_personality_v0: function() {
},
@@ -4827,15 +4811,6 @@ LibraryManager.library = {
llvm_log_f64: 'Math_log',
llvm_exp_f32: 'Math_exp',
llvm_exp_f64: 'Math_exp',
- ldexp: function(x, exp_) {
- return x * Math.pow(2, exp_);
- },
- ldexpf: 'ldexp',
- scalb: 'ldexp',
- scalbn: 'ldexp',
- scalbnf: 'ldexp',
- scalbln: 'ldexp',
- scalblnf: 'ldexp',
cbrt: function(x) {
return Math.pow(x, 1/3);
},
@@ -4843,11 +4818,11 @@ LibraryManager.library = {
cbrtl: 'cbrt',
modf: function(x, intpart) {
- {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}}
+ {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'double') }}};
return x - {{{ makeGetValue('intpart', 0, 'double') }}};
},
modff: function(x, intpart) {
- {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}}
+ {{{ makeSetValue('intpart', 0, 'Math.floor(x)', 'float') }}};
return x - {{{ makeGetValue('intpart', 0, 'float') }}};
},
frexp: function(x, exp_addr) {
@@ -4863,7 +4838,7 @@ LibraryManager.library = {
if (exp_ === raw_exp) exp_ += 1;
sig = sign*x/Math.pow(2, exp_);
}
- {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}}
+ {{{ makeSetValue('exp_addr', 0, 'exp_', 'i32') }}};
return sig;
},
frexpf: 'frexp',
@@ -5371,7 +5346,7 @@ LibraryManager.library = {
time: function(ptr) {
var ret = Math.floor(Date.now()/1000);
if (ptr) {
- {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}}
+ {{{ makeSetValue('ptr', 0, 'ret', 'i32') }}};
}
return ret;
},
@@ -5398,9 +5373,9 @@ LibraryManager.library = {
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_min, 'i32') }}},
{{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}},
0).getTime() / 1000;
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'new Date(timestamp).getDay()', 'i32') }}};
var yday = Math.round((timestamp - (new Date(year, 0, 1)).getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
return timestamp;
},
timelocal: 'mktime',
@@ -5413,15 +5388,15 @@ LibraryManager.library = {
gmtime_r__deps: ['__tm_timezone'],
gmtime_r: function(time, tmPtr) {
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getUTCMinutes()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getUTCHours()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getUTCDate()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getUTCMonth()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getUTCFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getUTCDay()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '0', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}};
var start = new Date(date); // define date using UTC, start from Jan 01 00:00:00 UTC
start.setUTCDate(1);
start.setUTCMonth(0);
@@ -5430,8 +5405,8 @@ LibraryManager.library = {
start.setUTCSeconds(0);
start.setUTCMilliseconds(0);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}};
return tmPtr;
},
@@ -5454,23 +5429,23 @@ LibraryManager.library = {
localtime_r: function(time, tmPtr) {
_tzset();
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_min, 'date.getMinutes()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_hour, 'date.getHours()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mday, 'date.getDate()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'date.getMonth()', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}};
var start = new Date(date.getFullYear(), 0, 1);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}};
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, 'start.getTimezoneOffset() * 60', 'i32') }}};
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_isdst, 'dst', 'i32') }}};
- {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}}
+ {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_zone, '___tm_timezone', 'i32') }}};
return tmPtr;
},
@@ -5488,9 +5463,9 @@ LibraryManager.library = {
var timePart = formatted.match(/\d{2}:\d{2}:\d{2}/)[0];
formatted = datePart + timePart + ' ' + date.getFullYear() + '\n';
formatted.split('').forEach(function(chr, index) {
- {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}}
+ {{{ makeSetValue('buf', 'index', 'chr.charCodeAt(0)', 'i8') }}};
});
- {{{ makeSetValue('buf', '25', '0', 'i8') }}}
+ {{{ makeSetValue('buf', '25', '0', 'i8') }}};
return buf;
},
@@ -5520,18 +5495,18 @@ LibraryManager.library = {
if (_tzset.called) return;
_tzset.called = true;
- {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_timezone'), '0', '-(new Date()).getTimezoneOffset() * 60', 'i32') }}};
var winter = new Date(2000, 0, 1);
var summer = new Date(2000, 6, 1);
- {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_daylight'), '0', 'Number(winter.getTimezoneOffset() != summer.getTimezoneOffset())', 'i32') }}};
var winterName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | winter.toString().match(/\(([A-Z]+)\)/)[1];
var summerName = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | summer.toString().match(/\(([A-Z]+)\)/)[1];
var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
- {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}}
- {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}}
+ {{{ makeSetValue(makeGlobalUse('_tzname'), '0', 'winterNamePtr', 'i32') }}};
+ {{{ makeSetValue(makeGlobalUse('_tzname'), Runtime.QUANTUM_SIZE, 'summerNamePtr', 'i32') }}};
},
stime__deps: ['$ERRNO_CODES', '__setErrNo'],
@@ -6101,15 +6076,15 @@ LibraryManager.library = {
*/
var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0);
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}
- {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_sec, 'fullDate.getSeconds()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_min, 'fullDate.getMinutes()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_hour, 'fullDate.getHours()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mday, 'fullDate.getDate()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}};
+ {{{ makeSetValue('tm', C_STRUCTS.tm.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
@@ -6140,8 +6115,8 @@ LibraryManager.library = {
var seconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_sec, 'i32') }}};
var nanoseconds = {{{ makeGetValue('rqtp', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
if (rmtp !== 0) {
- {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}}
- {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}}
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_sec, '0', 'i32') }}};
+ {{{ makeSetValue('rmtp', C_STRUCTS.timespec.tv_nsec, '0', 'i32') }}};
}
return _usleep((seconds * 1e6) + (nanoseconds / 1000));
},
@@ -6172,7 +6147,7 @@ LibraryManager.library = {
} else {
nsec = _emscripten_get_now_res();
}
- {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}}
+ {{{ makeSetValue('res', C_STRUCTS.timespec.tv_sec, '1', 'i32') }}};
{{{ makeSetValue('res', C_STRUCTS.timespec.tv_nsec, 'nsec', 'i32') }}} // resolution is milliseconds
return 0;
},
@@ -6853,7 +6828,7 @@ LibraryManager.library = {
__setErrNo__postset: '___errno_state = Runtime.staticAlloc(4); {{{ makeSetValue("___errno_state", 0, 0, "i32") }}};',
__setErrNo: function(value) {
// For convenient setting and returning of errno.
- {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}}
+ {{{ makeSetValue('___errno_state', '0', 'value', 'i32') }}};
return value;
},
__errno_location__deps: ['__setErrNo'],
@@ -6877,15 +6852,14 @@ LibraryManager.library = {
// int setrlimit(int resource, const struct rlimit *rlp)
return 0;
},
- __01getrlimit64_: 'getrlimit',
// TODO: Implement for real. We just do time used, and no useful data
getrusage: function(resource, rlp) {
// int getrusage(int resource, struct rusage *rlp);
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}}
- {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}}
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_sec, '1', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_utime.tv_usec, '2', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_sec, '3', 'i32') }}};
+ {{{ makeSetValue('rlp', C_STRUCTS.rusage.ru_stime.tv_usec, '4', 'i32') }}};
return 0;
},
@@ -6949,8 +6923,8 @@ LibraryManager.library = {
void **restrict stackaddr, size_t *restrict stacksize); */
/*FIXME: assumes that there is only one thread, and that attr is the
current thread*/
- {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}}
- {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}}
+ {{{ makeSetValue('stackaddr', '0', 'STACK_BASE', 'i8*') }}};
+ {{{ makeSetValue('stacksize', '0', 'TOTAL_STACK', 'i32') }}};
return 0;
},
@@ -6968,7 +6942,7 @@ LibraryManager.library = {
if (key == 0) {
return ERRNO_CODES.EINVAL;
}
- {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}}
+ {{{ makeSetValue('key', '0', 'PTHREAD_SPECIFIC_NEXT_KEY', 'i32*') }}};
// values start at 0
PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;
PTHREAD_SPECIFIC_NEXT_KEY++;
@@ -7026,7 +7000,7 @@ LibraryManager.library = {
posix_memalign__deps: ['memalign'],
posix_memalign: function(memptr, alignment, size) {
var ptr = _memalign(alignment, size);
- {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}}
+ {{{ makeSetValue('memptr', '0', 'ptr', 'i8*') }}};
return 0;
},
@@ -7068,7 +7042,7 @@ LibraryManager.library = {
if (addr === null) {
return 0;
}
- {{{ makeSetValue('inp', '0', 'addr', 'i32') }}}
+ {{{ makeSetValue('inp', '0', 'addr', 'i32') }}};
return 1;
},
@@ -7227,7 +7201,7 @@ LibraryManager.library = {
if (ret === null) {
return 0;
}
- {{{ makeSetValue('dst', '0', 'ret', 'i32') }}}
+ {{{ makeSetValue('dst', '0', 'ret', 'i32') }}};
return 1;
},
_inet_pton6_raw__deps: ['htons'],
@@ -7350,6 +7324,12 @@ LibraryManager.library = {
// netdb.h
// ==========================================================================
+ __h_errno_state: 'allocate(1, "i32", ALLOC_STATIC)',
+ __h_errno_location__deps: ['__h_errno_state'],
+ __h_errno_location: function() {
+ return ___h_errno_state;
+ },
+
// We can't actually resolve hostnames in the browser, so instead
// we're generating fake IP addresses with lookup_name that we can
// resolve later on with lookup_addr.
@@ -7405,6 +7385,7 @@ LibraryManager.library = {
gethostbyaddr: function (addr, addrlen, type) {
if (type !== {{{ cDefine('AF_INET') }}}) {
___setErrNo(ERRNO_CODES.EAFNOSUPPORT);
+ // TODO: set h_errno
return null;
}
addr = {{{ makeGetValue('addr', '0', 'i32') }}}; // addr is in_addr
@@ -7425,18 +7406,18 @@ LibraryManager.library = {
var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here
var nameBuf = _malloc(name.length+1);
writeStringToMemory(name, nameBuf);
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', 'i8*') }}};
var aliasesBuf = _malloc(4);
- {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}
+ {{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}};
var afinet = {{{ cDefine('AF_INET') }}};
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}};
var addrListBuf = _malloc(12);
- {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}}
- {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}}
- {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}}
- {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}}
+ {{{ makeSetValue('addrListBuf', '0', 'addrListBuf+8', 'i32*') }}};
+ {{{ makeSetValue('addrListBuf', '4', '0', 'i32*') }}};
+ {{{ makeSetValue('addrListBuf', '8', '__inet_pton4_raw(DNS.lookup_name(name))', 'i32') }}};
+ {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addr_list, 'addrListBuf', 'i8**') }}};
return ret;
},
@@ -9178,6 +9159,10 @@ LibraryManager.library = {
tempRet0 = 0;
return (high >>> (bits - 32))|0;
},
+
+ // misc shims for musl
+ __lockfile: function() { return 1 },
+ __unlockfile: function(){},
};
function autoAddDeps(object, name) {
@@ -9190,7 +9175,7 @@ function autoAddDeps(object, name) {
}
// Add aborting stubs for various libc stuff needed by libc++
-['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose', 'fputwc', '__lockfile', '__unlockfile'].forEach(function(aborter) {
+['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose'].forEach(function(aborter) {
LibraryManager.library[aborter] = function aborting_stub() { throw 'TODO: ' + aborter };
});
diff --git a/src/library_browser.js b/src/library_browser.js
index d5e35339..458a8dd2 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -775,6 +775,15 @@ mergeInto(LibraryManager.library, {
return;
}
+ // Signal GL rendering layer that processing of a new frame is about to start. This helps it optimize
+ // VBO double-buffering and reduce GPU stalls.
+#if FULL_ES2
+ GL.newRenderingFrameStarted();
+#endif
+#if LEGACY_GL_EMULATION
+ GL.newRenderingFrameStarted();
+#endif
+
if (Module['preMainLoop']) {
Module['preMainLoop']();
}
diff --git a/src/library_gl.js b/src/library_gl.js
index 17749590..61ca8957 100644
--- a/src/library_gl.js
+++ b/src/library_gl.js
@@ -57,6 +57,7 @@ var LibraryGL = {
unpackAlignment: 4, // default alignment is 4 bytes
init: function() {
+ GL.createLog2ceilLookup(GL.MAX_TEMP_BUFFER_SIZE);
Browser.moduleContextCreatedCallbacks.push(GL.initExtensions);
},
@@ -81,36 +82,58 @@ var LibraryGL = {
miniTempBuffer: null,
miniTempBufferViews: [0], // index i has the view of size i+1
- // Large temporary buffers
+ // When user GL code wants to render from client-side memory, we need to upload the vertex data to a temp VBO
+ // for rendering. Maintain a set of temp VBOs that are created-on-demand to appropriate sizes, and never destroyed.
+ // Also, for best performance the VBOs are double-buffered, i.e. every second frame we switch the set of VBOs we
+ // upload to, so that rendering from the previous frame is not disturbed by uploading from new data to it, which
+ // could cause a GPU-CPU pipeline stall.
+ // Note that index buffers are not double-buffered (at the moment) in this manner.
MAX_TEMP_BUFFER_SIZE: {{{ GL_MAX_TEMP_BUFFER_SIZE }}},
- tempBufferIndexLookup: null,
- tempVertexBuffers: null,
- tempIndexBuffers: null,
+ tempVertexBuffers1: [],
+ tempVertexBufferCounters1: [],
+ tempVertexBuffers2: [],
+ tempVertexBufferCounters2: [],
+ // Maximum number of temp VBOs of one size to maintain, after that we start reusing old ones, which is safe but can give
+ // a performance impact. If CPU-GPU stalls are a problem, increasing this might help.
+ numTempVertexBuffersPerSize: 64, // (const)
+ tempIndexBuffers: [],
tempQuadIndexBuffer: null,
- generateTempBuffers: function(quads) {
- GL.tempBufferIndexLookup = new Uint8Array(GL.MAX_TEMP_BUFFER_SIZE+1);
- GL.tempVertexBuffers = [];
- GL.tempIndexBuffers = [];
- var last = -1, curr = -1;
- var size = 1;
- for (var i = 0; i <= GL.MAX_TEMP_BUFFER_SIZE; i++) {
- if (i > size) {
- size <<= 1;
+ // Precompute a lookup table for the function ceil(log2(x)), i.e. how many bits are needed to represent x, or,
+ // if x was rounded up to next pow2, which index is the single '1' bit at?
+ // Then log2ceilLookup[x] returns ceil(log2(x)).
+ log2ceilLookup: null,
+ createLog2ceilLookup: function(maxValue) {
+ GL.log2ceilLookup = new Uint8Array(maxValue+1);
+ var log2 = 0;
+ var pow2 = 1;
+ GL.log2ceilLookup[0] = 0;
+ for(var i = 1; i <= maxValue; ++i) {
+ if (i > pow2) {
+ pow2 <<= 1;
+ ++log2;
}
- if (size != last) {
- curr++;
- GL.tempVertexBuffers[curr] = GLctx.createBuffer();
- GLctx.bindBuffer(GLctx.ARRAY_BUFFER, GL.tempVertexBuffers[curr]);
- GLctx.bufferData(GLctx.ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW);
- GLctx.bindBuffer(GLctx.ARRAY_BUFFER, null);
- GL.tempIndexBuffers[curr] = GLctx.createBuffer();
- GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[curr]);
- GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, size, GLctx.DYNAMIC_DRAW);
- GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, null);
- last = size;
+ GL.log2ceilLookup[i] = log2;
+ }
+ },
+
+ generateTempBuffers: function(quads) {
+ var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE];
+ GL.tempVertexBufferCounters1.length = GL.tempVertexBufferCounters2.length = largestIndex+1;
+ GL.tempVertexBuffers1.length = GL.tempVertexBuffers2.length = largestIndex+1;
+ GL.tempIndexBuffers.length = largestIndex+1;
+ for(var i = 0; i <= largestIndex; ++i) {
+ GL.tempIndexBuffers[i] = null; // Created on-demand
+ GL.tempVertexBufferCounters1[i] = GL.tempVertexBufferCounters2[i] = 0;
+ var ringbufferLength = GL.numTempVertexBuffersPerSize;
+ GL.tempVertexBuffers1[i] = [];
+ GL.tempVertexBuffers2[i] = [];
+ var ringbuffer1 = GL.tempVertexBuffers1[i];
+ var ringbuffer2 = GL.tempVertexBuffers2[i];
+ ringbuffer1.length = ringbuffer2.length = ringbufferLength;
+ for(var j = 0; j < ringbufferLength; ++j) {
+ ringbuffer1[j] = ringbuffer2[j] = null; // Created on-demand
}
- GL.tempBufferIndexLookup[i] = curr;
}
if (quads) {
@@ -140,6 +163,53 @@ var LibraryGL = {
}
},
+ getTempVertexBuffer: function getTempVertexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup[sizeBytes];
+ var ringbuffer = GL.tempVertexBuffers1[idx];
+ var nextFreeBufferIndex = GL.tempVertexBufferCounters1[idx];
+ GL.tempVertexBufferCounters1[idx] = (GL.tempVertexBufferCounters1[idx]+1) & (GL.numTempVertexBuffersPerSize-1);
+ var vbo = ringbuffer[nextFreeBufferIndex];
+ if (vbo) {
+ return vbo;
+ }
+ var prevVBO = GLctx.getParameter(GLctx.ARRAY_BUFFER_BINDING);
+ ringbuffer[nextFreeBufferIndex] = GLctx.createBuffer();
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, ringbuffer[nextFreeBufferIndex]);
+ GLctx.bufferData(GLctx.ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW);
+ GLctx.bindBuffer(GLctx.ARRAY_BUFFER, prevVBO);
+ return ringbuffer[nextFreeBufferIndex];
+ },
+
+ getTempIndexBuffer: function getTempIndexBuffer(sizeBytes) {
+ var idx = GL.log2ceilLookup[sizeBytes];
+ var ibo = GL.tempIndexBuffers[idx];
+ if (ibo) {
+ return ibo;
+ }
+ var prevIBO = GLctx.getParameter(GLctx.ELEMENT_ARRAY_BUFFER_BINDING);
+ GL.tempIndexBuffers[idx] = GLctx.createBuffer();
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, GL.tempIndexBuffers[idx]);
+ GLctx.bufferData(GLctx.ELEMENT_ARRAY_BUFFER, 1 << idx, GLctx.DYNAMIC_DRAW);
+ GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, prevIBO);
+ return GL.tempIndexBuffers[idx];
+ },
+
+ // Called at start of each new WebGL rendering frame. This swaps the doublebuffered temp VB memory pointers,
+ // so that every second frame utilizes different set of temp buffers. The aim is to keep the set of buffers
+ // being rendered, and the set of buffers being updated disjoint.
+ newRenderingFrameStarted: function newRenderingFrameStarted() {
+ var vb = GL.tempVertexBuffers1;
+ GL.tempVertexBuffers1 = GL.tempVertexBuffers2;
+ GL.tempVertexBuffers2 = vb;
+ vb = GL.tempVertexBufferCounters1;
+ GL.tempVertexBufferCounters1 = GL.tempVertexBufferCounters2;
+ GL.tempVertexBufferCounters2 = vb;
+ var largestIndex = GL.log2ceilLookup[GL.MAX_TEMP_BUFFER_SIZE];
+ for(var i = 0; i <= largestIndex; ++i) {
+ GL.tempVertexBufferCounters1[i] = 0;
+ }
+ },
+
// Find a token in a shader source string
findToken: function(source, token) {
function isIdentChar(ch) {
@@ -446,9 +516,6 @@ var LibraryGL = {
preDrawHandleClientVertexAttribBindings: function preDrawHandleClientVertexAttribBindings(count) {
GL.resetBufferBinding = false;
- var used = GL.usedTempBuffers;
- used.length = 0;
-
// TODO: initial pass to detect ranges we need to upload, might not need an upload per attrib
for (var i = 0; i < GL.maxVertexAttribs; ++i) {
var cb = GL.clientBuffers[i];
@@ -457,15 +524,7 @@ var LibraryGL = {
GL.resetBufferBinding = true;
var size = GL.calcBufLength(cb.size, cb.type, cb.stride, count);
- var index = GL.tempBufferIndexLookup[size];
- var buf;
- do {
-#if ASSERTIONS
- assert(index < GL.tempVertexBuffers.length);
-#endif
- buf = GL.tempVertexBuffers[index++];
- } while (used.indexOf(buf) >= 0);
- used.push(buf);
+ var buf = GL.getTempVertexBuffer(size);
GLctx.bindBuffer(GLctx.ARRAY_BUFFER, buf);
GLctx.bufferSubData(GLctx.ARRAY_BUFFER,
0,
@@ -2742,14 +2801,6 @@ var LibraryGL = {
this.key0 = -1; // The key of this texture unit must be recomputed when rendering the next time.
GLImmediate.currentRenderer = null; // The currently used renderer must be re-evaluated at next render.
}
- this.traverseState = function(keyView) {
- if (this.key0 == -1) {
- this.recomputeKey();
- }
- keyView.next(this.key0);
- keyView.next(this.key1);
- keyView.next(this.key2);
- };
}
function CTexUnit() {
@@ -2758,26 +2809,55 @@ var LibraryGL = {
this.enabled_tex2D = false;
this.enabled_tex3D = false;
this.enabled_texCube = false;
+ this.texTypesEnabled = 0; // A bitfield combination of the four flags above, used for fast access to operations.
this.traverseState = function CTexUnit_traverseState(keyView) {
- var texUnitType = this.getTexType();
- keyView.next(texUnitType);
- if (!texUnitType) return;
- this.env.traverseState(keyView);
+ if (this.texTypesEnabled) {
+ if (this.env.key0 == -1) {
+ this.env.recomputeKey();
+ }
+ keyView.next(this.texTypesEnabled | (this.env.key0 << 4));
+ keyView.next(this.env.key1);
+ keyView.next(this.env.key2);
+ } else {
+ // For correctness, must traverse a zero value, theoretically a subsequent integer key could collide with this value otherwise.
+ keyView.next(0);
+ }
};
};
// Class impls:
CTexUnit.prototype.enabled = function CTexUnit_enabled() {
- return this.getTexType() != 0;
+ return this.texTypesEnabled;
}
CTexUnit.prototype.genPassLines = function CTexUnit_genPassLines(passOutputVar, passInputVar, texUnitID) {
if (!this.enabled()) {
return ["vec4 " + passOutputVar + " = " + passInputVar + ";"];
}
-
- return this.env.genPassLines(passOutputVar, passInputVar, texUnitID);
+ var lines = this.env.genPassLines(passOutputVar, passInputVar, texUnitID).join('\n');
+
+ var texLoadLines = '';
+ var texLoadRegex = /(texture.*?\(.*?\))/g;
+ var loadCounter = 0;
+ var load;
+
+ // As an optimization, merge duplicate identical texture loads to one var.
+ while(load = texLoadRegex.exec(lines)) {
+ var texLoadExpr = load[1];
+ var secondOccurrence = lines.slice(load.index+1).indexOf(texLoadExpr);
+ if (secondOccurrence != -1) { // And also has a second occurrence of same load expression..
+ // Create new var to store the common load.
+ var prefix = TEXENVJIT_NAMESPACE_PREFIX + 'env' + texUnitID + "_";
+ var texLoadVar = prefix + 'texload' + loadCounter++;
+ var texLoadLine = 'vec4 ' + texLoadVar + ' = ' + texLoadExpr + ';\n';
+ texLoadLines += texLoadLine + '\n'; // Store the generated texture load statements in a temp string to not confuse regex search in progress.
+ lines = lines.split(texLoadExpr).join(texLoadVar);
+ // Reset regex search, since we modified the string.
+ texLoadRegex = /(texture.*\(.*\))/g;
+ }
+ }
+ return [texLoadLines + lines];
}
CTexUnit.prototype.getTexType = function CTexUnit_getTexType() {
@@ -2898,13 +2978,18 @@ var LibraryGL = {
var alphaLines = this.genCombinerLines(false, alphaVar,
passInputVar, texUnitID,
this.alphaCombiner, this.alphaSrc, this.alphaOp);
+
+ // Generate scale, but avoid generating an identity op that multiplies by one.
+ var scaledColor = (this.colorScale == 1) ? colorVar : (colorVar + " * " + valToFloatLiteral(this.colorScale));
+ var scaledAlpha = (this.alphaScale == 1) ? alphaVar : (alphaVar + " * " + valToFloatLiteral(this.alphaScale));
+
var line = [
"vec4 " + passOutputVar,
" = ",
"vec4(",
- colorVar + " * " + valToFloatLiteral(this.colorScale),
+ scaledColor,
", ",
- alphaVar + " * " + valToFloatLiteral(this.alphaScale),
+ scaledAlpha,
")",
";",
].join("");
@@ -3084,12 +3169,7 @@ var LibraryGL = {
traverseState: function(keyView) {
for (var i = 0; i < s_texUnits.length; i++) {
- var texUnit = s_texUnits[i];
- var enabled = texUnit.enabled();
- keyView.next(enabled);
- if (enabled) {
- texUnit.traverseState(keyView);
- }
+ s_texUnits[i].traverseState(keyView);
}
},
@@ -3113,24 +3193,28 @@ var LibraryGL = {
if (!cur.enabled_tex1D) {
GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
cur.enabled_tex1D = true;
+ cur.texTypesEnabled |= 1;
}
break;
case GL_TEXTURE_2D:
if (!cur.enabled_tex2D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex2D = true;
+ cur.texTypesEnabled |= 2;
}
break;
case GL_TEXTURE_3D:
if (!cur.enabled_tex3D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex3D = true;
+ cur.texTypesEnabled |= 4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (!cur.enabled_texCube) {
GLImmediate.currentRenderer = null;
cur.enabled_texCube = true;
+ cur.texTypesEnabled |= 8;
}
break;
}
@@ -3143,24 +3227,28 @@ var LibraryGL = {
if (cur.enabled_tex1D) {
GLImmediate.currentRenderer = null; // Renderer state changed, and must be recreated or looked up again.
cur.enabled_tex1D = false;
+ cur.texTypesEnabled &= ~1;
}
break;
case GL_TEXTURE_2D:
if (cur.enabled_tex2D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex2D = false;
+ cur.texTypesEnabled &= ~2;
}
break;
case GL_TEXTURE_3D:
if (cur.enabled_tex3D) {
GLImmediate.currentRenderer = null;
cur.enabled_tex3D = false;
+ cur.texTypesEnabled &= ~4;
}
break;
case GL_TEXTURE_CUBE_MAP:
if (cur.enabled_texCube) {
GLImmediate.currentRenderer = null;
cur.enabled_texCube = false;
+ cur.texTypesEnabled &= ~8;
}
break;
}
@@ -3434,7 +3522,6 @@ var LibraryGL = {
// we maintain a cache of renderers, optimized to not generate garbage
var attributes = GLImmediate.liveClientAttributes;
var cacheMap = GLImmediate.rendererCache;
- var temp;
var keyView = cacheMap.getStaticKeyView().reset();
// By attrib state:
@@ -3442,7 +3529,6 @@ var LibraryGL = {
for (var i = 0; i < attributes.length; i++) {
enabledAttributesKey |= 1 << attributes[i].name;
}
- keyView.next(enabledAttributesKey);
// By fog state:
var fogParam = 0;
@@ -3459,13 +3545,17 @@ var LibraryGL = {
break;
}
}
- keyView.next(fogParam);
+ keyView.next((enabledAttributesKey << 2) | fogParam);
+#if !GL_FFP_ONLY
// By cur program:
keyView.next(GL.currProgram);
if (!GL.currProgram) {
+#endif
GLImmediate.TexEnvJIT.traverseState(keyView);
+#if !GL_FFP_ONLY
}
+#endif
// If we don't already have it, create it.
var renderer = keyView.get();
@@ -3720,7 +3810,7 @@ var LibraryGL = {
#if ASSERTIONS
assert(end <= GL.MAX_TEMP_BUFFER_SIZE, 'too much vertex data');
#endif
- arrayBuffer = GL.tempVertexBuffers[GL.tempBufferIndexLookup[end]];
+ arrayBuffer = GL.getTempVertexBuffer(end);
// TODO: consider using the last buffer we bound, if it was larger. downside is larger buffer, but we might avoid rebinding and preparing
} else {
arrayBuffer = GL.currArrayBuffer;
@@ -4028,11 +4118,12 @@ var LibraryGL = {
if (!Module.useWebGL) return; // a 2D canvas may be currently used TODO: make sure we are actually called in that case
- GLImmediate.TexEnvJIT.init(GLctx);
-
// User can override the maximum number of texture units that we emulate. Using fewer texture units increases runtime performance
// slightly, so it is advantageous to choose as small value as needed.
GLImmediate.MAX_TEXTURES = Module['GL_MAX_TEXTURE_IMAGE_UNITS'] || GLctx.getParameter(GLctx.MAX_TEXTURE_IMAGE_UNITS);
+
+ GLImmediate.TexEnvJIT.init(GLctx, GLImmediate.MAX_TEXTURES);
+
GLImmediate.NUM_ATTRIBUTES = 3 /*pos+normal+color attributes*/ + GLImmediate.MAX_TEXTURES;
GLImmediate.clientAttributes = [];
GLEmulation.enabledClientAttribIndices = [];
@@ -4170,7 +4261,7 @@ var LibraryGL = {
}
for (var i = 0; i < attributes.length; i++) {
var attr = attributes[i];
- attr.offset = attr.pointer - clientStartPointer; // Compute what will be the offset of this attribute in the VBO after we upload.
+ attr.offset = attr.pointer - GLImmediate.vertexPointer; // Compute what will be the offset of this attribute in the VBO after we upload.
}
GLImmediate.stride = Math.max(maxStride, bytes);
}
@@ -4221,7 +4312,7 @@ var LibraryGL = {
#if ASSERTIONS
assert(numProvidedIndexes << 1 <= GL.MAX_TEMP_BUFFER_SIZE, 'too many immediate mode indexes (a)');
#endif
- var indexBuffer = GL.tempIndexBuffers[GL.tempBufferIndexLookup[numProvidedIndexes << 1]];
+ var indexBuffer = GL.getTempIndexBuffer(numProvidedIndexes << 1);
GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, indexBuffer);
GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER, 0, {{{ makeHEAPView('U16', 'ptr', 'ptr + (numProvidedIndexes << 1)') }}});
ptr = 0;
@@ -4986,7 +5077,7 @@ var LibraryGL = {
var buf;
if (!GL.currElementArrayBuffer) {
var size = GL.calcBufLength(1, type, 0, count);
- buf = GL.tempIndexBuffers[GL.tempBufferIndexLookup[size]];
+ buf = GL.getTempIndexBuffer(size);
GLctx.bindBuffer(GLctx.ELEMENT_ARRAY_BUFFER, buf);
GLctx.bufferSubData(GLctx.ELEMENT_ARRAY_BUFFER,
0,
diff --git a/src/library_glew.js b/src/library_glew.js
new file mode 100644
index 00000000..f7da5f82
--- /dev/null
+++ b/src/library_glew.js
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * EMSCRIPTEN GLEW 1.10.0 emulation
+ *
+ * What it does:
+ * - Stubs init function.
+ * - GL Extensions support.
+ *
+ * Optional:
+ * - isLinaroFork variable to enable glew-es specific error strings.
+ * This is enabled by default, but should be disabled when upstream glew conflicts.
+ *
+ * Authors:
+ * - Jari Vetoniemi <mailroxas@gmail.com>
+ ******************************************************************************/
+
+var LibraryGLEW = {
+ $GLEW__deps: ['glGetString'],
+ $GLEW: {
+ isLinaroFork: 1,
+ extensions: null,
+
+ error: {
+ 0:null, // GLEW_OK || GLEW_NO_ERROR
+ 1:null, // GLEW_ERROR_NO_GL_VERSION
+ 2:null, // GLEW_ERROR_GL_VERSION_10_ONLY
+ 3:null, // GLEW_ERROR_GLX_VERSION_11_ONLY
+
+ 4:null, // GLEW_ERROR_NOT_GLES_VERSION
+ 5:null, // GLEW_ERROR_GLES_VERSION
+ 6:null, // GLEW_ERROR_NO_EGL_VERSION
+ 7:null, // GLEW_ERROR_EGL_VERSION_10_ONLY
+
+ 8:null, // Unknown error
+ },
+
+ version: {
+ 1:null, // GLEW_VERSION
+ 2:null, // GLEW_VERSION_MAJOR
+ 3:null, // GLEW_VERSION_MINOR
+ 4:null, // GLEW_VERSION_MICRO
+ },
+
+ errorStringConstantFromCode: function(error) {
+ if (GLEW.isLinaroFork) {
+ switch (error) {
+ case 4:return "OpenGL ES lib expected, found OpenGL lib"; // GLEW_ERROR_NOT_GLES_VERSION
+ case 5:return "OpenGL lib expected, found OpenGL ES lib"; // GLEW_ERROR_GLES_VERSION
+ case 6:return "Missing EGL version"; // GLEW_ERROR_NO_EGL_VERSION
+ case 7:return "EGL 1.1 and up are supported"; // GLEW_ERROR_EGL_VERSION_10_ONLY
+ default:break;
+ }
+ }
+
+ switch (error) {
+ case 0:return "No error"; // GLEW_OK || GLEW_NO_ERROR
+ case 1:return "Missing GL version"; // GLEW_ERROR_NO_GL_VERSION
+ case 2:return "GL 1.1 and up are supported"; // GLEW_ERROR_GL_VERSION_10_ONLY
+ case 3:return "GLX 1.2 and up are supported"; // GLEW_ERROR_GLX_VERSION_11_ONLY
+ default:return null;
+ }
+ },
+
+ errorString: function(error) {
+ if (!GLEW.error[error]) {
+ var string = GLEW.errorStringConstantFromCode(error);
+ if (!string) {
+ string = "Unknown error";
+ error = 8; // prevent array from growing more than this
+ }
+ GLEW.error[error] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL);
+ }
+ return GLEW.error[error];
+ },
+
+ versionStringConstantFromCode: function(name) {
+ switch (name) {
+ case 1:return "1.10.0"; // GLEW_VERSION
+ case 2:return "1"; // GLEW_VERSION_MAJOR
+ case 3:return "10"; // GLEW_VERSION_MINOR
+ case 4:return "0"; // GLEW_VERSION_MICRO
+ default:return null;
+ }
+ },
+
+ versionString: function(name) {
+ if (!GLEW.version[name]) {
+ var string = GLEW.versionStringConstantFromCode(name);
+ if (!string)
+ return 0;
+ GLEW.version[name] = allocate(intArrayFromString(string), 'i8', ALLOC_NORMAL);
+ }
+ return GLEW.version[name];
+ },
+
+ extensionIsSupported: function(name) {
+ if (!GLEW.extensions) {
+ GLEW.extensions = Pointer_stringify(_glGetString(0x1F03)).split(' ');
+ }
+
+ if (GLEW.extensions.indexOf(name) != -1)
+ return 1;
+
+ // extensions from GLEmulations do not come unprefixed
+ // so, try with prefix
+ return (GLEW.extensions.indexOf("GL_" + name) != -1);
+ },
+ },
+
+ glewInit: function() { return 0; },
+
+ glewIsSupported: function(name) {
+ var exts = Pointer_stringify(name).split(' ');
+ for (i in exts) {
+ if (!GLEW.extensionIsSupported(exts[i]))
+ return 0;
+ }
+ return 1;
+ },
+
+ glewGetExtension: function(name) {
+ return GLEW.extensionIsSupported(Pointer_stringify(name));
+ },
+
+ glewGetErrorString: function(error) {
+ return GLEW.errorString(error);
+ },
+
+ glewGetString: function(name) {
+ return GLEW.versionString(name);
+ },
+
+};
+
+autoAddDeps(LibraryGLEW, '$GLEW');
+mergeInto(LibraryManager.library, LibraryGLEW);
diff --git a/src/library_sdl.js b/src/library_sdl.js
index fc38dd1c..5a111289 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -232,17 +232,17 @@ var LibrarySDL = {
{{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.pixels, 'buffer', 'void*') }}} // SDL_Surface.pixels
{{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.clip_rect, '0', 'i32*') }}} // SDL_Surface.offset
- {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}
+ {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}};
{{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}} // SDL_PIXELFORMAT_RGBA8888
{{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}} // TODO
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}};
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}}
- {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}}
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Rmask, 'rmask || 0x000000ff', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Gmask, 'gmask || 0x0000ff00', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Bmask, 'bmask || 0x00ff0000', 'i32') }}};
+ {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.Amask, 'amask || 0xff000000', 'i32') }}};
// Decide if we want to use WebGL or not
var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL
@@ -592,19 +592,19 @@ var LibrarySDL = {
scan = SDL.scanCodes[key] || key;
}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.state, 'down ? 1 : 0', 'i8') }}};
{{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.repeat, '0', 'i8') }}} // TODO
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}}
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.scancode, 'scan', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.sym, 'key', 'i32') }}};
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.mod, 'SDL.modState', 'i16') }}};
// some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode.
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_KeyboardEvent.keysym + C_STRUCTS.SDL_Keysym.unicode, 'event.keypressCharCode || key', 'i32') }}};
break;
}
case 'keypress': {
- {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}}
+ {{{ makeSetValue('ptr', C_STRUCTS.SDL_TextInputEvent.type, 'SDL.DOMEventToSDLEvent[event.type]', 'i32') }}};
// Not filling in windowID for now
var cStr = intArrayFromString(String.fromCharCode(event.charCode));
for (var i = 0; i < cStr.length; ++i) {
@@ -819,9 +819,9 @@ var LibrarySDL = {
SDL_Linked_Version: function() {
if (SDL.version === null) {
SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}});
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}}
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}}
- {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}}
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.major, '0', '1', 'i8') }}};
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.minor, '0', '3', 'i8') }}};
+ {{{ makeSetValue('SDL.version + ' + C_STRUCTS.SDL_version.patch, '0', '0', 'i8') }}};
}
return SDL.version;
},
@@ -881,9 +881,9 @@ var LibrarySDL = {
var ret = _malloc(5*Runtime.QUANTUM_SIZE);
{{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*0', '0', '0', 'i32') }}} // TODO
{{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*1', '0', '0', 'i32') }}} // TODO
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}}
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}}
- {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}}
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*2', '0', '0', 'void*') }}};
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*3', '0', 'Module["canvas"].width', 'i32') }}};
+ {{{ makeSetValue('ret+Runtime.QUANTUM_SIZE*4', '0', 'Module["canvas"].height', 'i32') }}};
return ret;
},
diff --git a/src/modules.js b/src/modules.js
index c0b98f6f..ad467ba7 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -424,7 +424,7 @@ var LibraryManager = {
load: function() {
if (this.library) return;
- var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js'].concat(additionalLibraries);
+ var libraries = ['library.js', 'library_path.js', 'library_fs.js', 'library_idbfs.js', 'library_memfs.js', 'library_nodefs.js', 'library_sockfs.js', 'library_tty.js', 'library_browser.js', 'library_sdl.js', 'library_gl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', 'library_gc.js', 'library_jansson.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', 'library_glew.js'].concat(additionalLibraries);
for (var i = 0; i < libraries.length; i++) {
eval(processMacros(preprocess(read(libraries[i]))));
}
diff --git a/src/parseTools.js b/src/parseTools.js
index 4d6d7bd3..1c70a018 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -962,8 +962,13 @@ function parseNumerical(value, type) {
}
if (isNumber(value)) {
var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50
+ // type may be undefined here, like when this is called from makeConst with a single argument.
+ // but if it is a number, then we can safely assume that this should handle negative zeros
+ // correctly.
+ if (type === undefined || type === 'double' || type === 'float') {
+ if (value[0] === '-' && ret === 0) { return '-.0'; } // fix negative 0, toString makes it 0
+ }
if (type === 'double' || type === 'float') {
- if (value[0] === '-' && ret === 0) return '-.0'; // fix negative 0, toString makes it 0
if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type);
}
return ret.toString();
@@ -1322,18 +1327,22 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align, noSa
var printType = type;
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
if (printType[0] === '#') printType = printType.substr(1);
- return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type);
- } else {
- var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
- if (ASM_JS && (phase == 'funcs' || forceAsm)) {
- ret = asmCoercion(ret, type);
- }
- if (ASM_HEAP_LOG) {
- ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret,
- 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int'));
+ if (ASM_JS) {
+ if (!ignore) return asmCoercion('SAFE_HEAP_LOAD(' + asmCoercion(offset, 'i32') + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ', ' + (!!unsigned+0) + ')', type);
+ // else fall through
+ } else {
+ return asmCoercion('SAFE_HEAP_LOAD(' + offset + ', ' + (ASM_JS ? 0 : printType) + ', ' + (!!unsigned+0) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')', type);
}
- return ret;
}
+ var ret = makeGetSlabs(ptr, type, false, unsigned)[0] + '[' + getHeapOffset(offset, type, forceAsm) + ']';
+ if (ASM_JS && (phase == 'funcs' || forceAsm)) {
+ ret = asmCoercion(ret, type);
+ }
+ if (ASM_HEAP_LOG) {
+ ret = makeInlineCalculation('(asmPrint' + (type in Runtime.FLOAT_TYPES ? 'Float' : 'Int') + '(' + (asmPrintCounter++) + ',' + asmCoercion('VALUE', type) + '), VALUE)', ret,
+ 'temp' + (type in Runtime.FLOAT_TYPES ? 'Double' : 'Int'));
+ }
+ return ret;
}
function makeGetValueAsm(ptr, pos, type, unsigned) {
@@ -1430,10 +1439,14 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe,
var printType = type;
if (printType !== 'null' && printType[0] !== '#') printType = '"' + safeQuote(printType) + '"';
if (printType[0] === '#') printType = printType.substr(1);
- return 'SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
- } else {
- return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
+ if (ASM_JS) {
+ if (!ignore) return asmCoercion('SAFE_HEAP_STORE(' + asmCoercion(offset, 'i32') + ', ' + asmCoercion(value, type) + ', ' + Runtime.getNativeTypeSize(type) + ', ' + ((type in Runtime.FLOAT_TYPES)|0) + ')', type);
+ // else fall through
+ } else {
+ return 'SAFE_HEAP_STORE(' + offset + ', ' + value + ', ' + (ASM_JS ? 0 : printType) + ', ' + ((!checkSafeHeap() || ignore)|0) + ')';
+ }
}
+ return makeGetSlabs(ptr, type, true).map(function(slab) { return slab + '[' + getHeapOffset(offset, type, forceAsm) + ']=' + value }).join(sep);
}
function makeSetValueAsm(ptr, pos, value, type, noNeedFirst, ignore, align, noSafe, sep, forcedAlign) {
@@ -1776,31 +1789,12 @@ function makePointer(slab, pos, allocator, type, ptr, finalMemoryInitialization)
types = 'i8';
}
- // JS engines sometimes say array initializers are too large. Work around that by chunking and calling concat to combine at runtime
- var chunkSize = JS_CHUNK_SIZE;
- function chunkify(array) {
- // break very large slabs into parts
- var ret = '';
- var index = 0;
- while (index < array.length) {
- ret = (ret ? ret + '.concat(' : '') + '[' + array.slice(index, index + chunkSize).map(JSON.stringify) + ']' + (ret ? ')\n' : '');
- index += chunkSize;
- }
- return ret;
- }
- if (typeof slab == 'object' && slab.length > chunkSize) {
- slab = chunkify(slab);
- }
if (typeof types == 'object') {
while (types.length < slab.length) types.push(0);
}
- if (typeof types != 'string' && types.length > chunkSize) {
- types = chunkify(types);
- } else {
- types = JSON.stringify(types);
- }
+ types = JSON.stringify(types);
if (typeof slab == 'object') slab = '[' + slab.join(',') + ']';
- return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ')';
+ return 'allocate(' + slab + ', ' + types + (allocator ? ', ' + allocator : '') + (allocator == 'ALLOC_NONE' ? ', ' + ptr : '') + ');';
}
function makeGetSlabs(ptr, type, allowMultiple, unsigned) {
@@ -2145,9 +2139,9 @@ function makeRounding(value, bits, signed, floatConversion) {
}
}
// Math.floor is reasonably fast if we don't care about corrections (and even correct if unsigned)
- if (!correctRoundings() || !signed) return 'Math_floor(' + value + ')';
+ if (!correctRoundings() || !signed) return '(+Math_floor(' + value + '))';
// We are left with >32 bits
- return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? Math_floor(VALUE) : Math_ceil(VALUE)', value, 'tempBigIntR');
+ return makeInlineCalculation(makeComparison('VALUE', '>=', '0', 'float') + ' ? +Math_floor(VALUE) : +Math_ceil(VALUE)', value, 'tempBigIntR');
}
}
diff --git a/src/postamble.js b/src/postamble.js
index d6c059b8..90a86474 100644
--- a/src/postamble.js
+++ b/src/postamble.js
@@ -121,12 +121,13 @@ function run(args) {
if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
function doRun() {
+ if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
+ Module['calledRun'] = true;
+
ensureInitRuntime();
preMain();
- assert(!Module['calledRun']);
- Module['calledRun'] = true;
if (Module['_main'] && shouldRunNow) {
Module['callMain'](args);
}
diff --git a/src/preamble.js b/src/preamble.js
index ac6ee7b3..d415b87e 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -21,6 +21,7 @@ Module.print = Module.printErr = function(){};
#endif
#if SAFE_HEAP
+#if ASM_JS == 0
//========================================
// Debugging tools - Heap
//========================================
@@ -166,6 +167,41 @@ function SAFE_HEAP_FILL_HISTORY(from, to, type) {
}
//==========================================
+#else
+// ASM_JS safe heap
+
+function getSafeHeapType(bytes, isFloat) {
+ switch (bytes) {
+ case 1: return 'i8';
+ case 2: return 'i16';
+ case 4: return isFloat ? 'float' : 'i32';
+ case 8: return 'double';
+ default: assert(0);
+ }
+}
+
+function SAFE_HEAP_STORE(dest, value, bytes, isFloat) {
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]);
+#endif
+ assert(dest > 0, 'segmentation fault');
+ assert(dest % bytes === 0);
+ setValue(dest, value, getSafeHeapType(bytes, isFloat), 1);
+}
+
+function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) {
+#if SAFE_HEAP_LOG
+ Module.print('SAFE_HEAP load: ' + [dest, bytes, isFloat, unsigned]);
+#endif
+ assert(dest > 0, 'segmentation fault');
+ assert(dest % bytes === 0);
+ var type = getSafeHeapType(bytes, isFloat);
+ var ret = getValue(dest, type, 1);
+ if (unsigned) ret = unSign(ret, parseInt(type.substr(1)), 1);
+ return ret;
+}
+
+#endif
#endif
#if CHECK_HEAP_ALIGN
diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp
index 389d7447..204986da 100644
--- a/src/relooper/Relooper.cpp
+++ b/src/relooper/Relooper.cpp
@@ -40,27 +40,56 @@ static void PutIndented(const char *String);
static char *OutputBufferRoot = NULL;
static char *OutputBuffer = NULL;
static int OutputBufferSize = 0;
+static int OutputBufferOwned = false;
+
+static int LeftInOutputBuffer() {
+ return OutputBufferSize - (OutputBuffer - OutputBufferRoot);
+}
+
+static bool EnsureOutputBuffer(int Needed) { // ensures the output buffer is sufficient. returns true is no problem happened
+ Needed++; // ensure the trailing \0 is not forgotten
+ int Left = LeftInOutputBuffer();
+ if (!OutputBufferOwned) {
+ assert(Needed < Left);
+ } else {
+ // we own the buffer, and can resize if necessary
+ if (Needed >= Left) {
+ int Offset = OutputBuffer - OutputBufferRoot;
+ int TotalNeeded = OutputBufferSize + Needed - Left + 10240;
+ int NewSize = OutputBufferSize;
+ while (NewSize < TotalNeeded) NewSize = NewSize + (NewSize/2);
+ //printf("resize %d => %d\n", OutputBufferSize, NewSize);
+ OutputBufferRoot = (char*)realloc(OutputBufferRoot, NewSize);
+ OutputBuffer = OutputBufferRoot + Offset;
+ OutputBufferSize = NewSize;
+ return false;
+ }
+ }
+ return true;
+}
void PrintIndented(const char *Format, ...) {
assert(OutputBuffer);
- assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize);
+ EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION);
for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' ';
- va_list Args;
- va_start(Args, Format);
- int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot);
- int written = vsnprintf(OutputBuffer, left, Format, Args);
- assert(written < left);
- OutputBuffer += written;
- va_end(Args);
+ int Written;
+ while (1) { // write and potentially resize buffer until we have enough room
+ int Left = LeftInOutputBuffer();
+ va_list Args;
+ va_start(Args, Format);
+ Written = vsnprintf(OutputBuffer, Left, Format, Args);
+ va_end(Args);
+ if (EnsureOutputBuffer(Written)) break;
+ }
+ OutputBuffer += Written;
}
void PutIndented(const char *String) {
assert(OutputBuffer);
- assert(OutputBuffer + Indenter::CurrIndent*INDENTATION - OutputBufferRoot < OutputBufferSize);
+ EnsureOutputBuffer(Indenter::CurrIndent*INDENTATION);
for (int i = 0; i < Indenter::CurrIndent*INDENTATION; i++, OutputBuffer++) *OutputBuffer = ' ';
- int left = OutputBufferSize - (OutputBuffer - OutputBufferRoot);
- int needed = strlen(String)+1;
- assert(needed < left);
+ int Needed = strlen(String)+1;
+ EnsureOutputBuffer(Needed);
strcpy(OutputBuffer, String);
OutputBuffer += strlen(String);
*OutputBuffer++ = '\n';
@@ -293,12 +322,26 @@ void MultipleShape::RenderLoopPostfix() {
void MultipleShape::Render(bool InLoop) {
RenderLoopPrefix();
- bool First = true;
+
+ // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here
+ typedef std::map<int, Shape*> IdShapeMap;
+ IdShapeMap IdMap;
for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) {
+ int Id = iter->first->Id;
+ IdShapeMap::iterator Test = IdMap.find(Id);
+ if (Test != IdMap.end()) {
+ assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else
+ continue;
+ }
+ IdMap[iter->first->Id] = iter->second;
+ }
+
+ bool First = true;
+ for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) {
if (AsmJS) {
- PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first->Id);
+ PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first);
} else {
- PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first->Id);
+ PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first);
}
First = false;
Indenter::Indent();
@@ -362,8 +405,8 @@ Relooper::~Relooper() {
for (unsigned i = 0; i < Shapes.size(); i++) delete Shapes[i];
}
-void Relooper::AddBlock(Block *New) {
- New->Id = BlockIdCounter++;
+void Relooper::AddBlock(Block *New, int Id) {
+ New->Id = Id == -1 ? BlockIdCounter++ : Id;
Blocks.push_back(New);
}
@@ -417,8 +460,7 @@ void Relooper::Calculate(Block *Entry) {
for (BlockSet::iterator iter = Original->BranchesIn.begin(); iter != Original->BranchesIn.end(); iter++) {
Block *Prior = *iter;
Block *Split = new Block(Original->Code, Original->BranchVar);
- Parent->AddBlock(Split);
- PrintDebug(" to %d\n", Split->Id);
+ Parent->AddBlock(Split, Original->Id);
Split->BranchesIn.insert(Prior);
Branch *Details = Prior->BranchesOut[Original];
Prior->BranchesOut[Split] = new Branch(Details->Condition, Details->Code);
@@ -1158,11 +1200,18 @@ void Relooper::Render() {
void Relooper::SetOutputBuffer(char *Buffer, int Size) {
OutputBufferRoot = OutputBuffer = Buffer;
OutputBufferSize = Size;
+ OutputBufferOwned = false;
}
void Relooper::MakeOutputBuffer(int Size) {
+ if (OutputBufferRoot && OutputBufferSize >= Size && OutputBufferOwned) return;
OutputBufferRoot = OutputBuffer = (char*)malloc(Size);
OutputBufferSize = Size;
+ OutputBufferOwned = true;
+}
+
+char *Relooper::GetOutputBuffer() {
+ return OutputBufferRoot;
}
void Relooper::SetAsmJSMode(int On) {
diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h
index dfabcabb..85adf359 100644
--- a/src/relooper/Relooper.h
+++ b/src/relooper/Relooper.h
@@ -57,7 +57,7 @@ struct Block {
BlockBranchMap ProcessedBranchesOut;
BlockSet ProcessedBranchesIn;
Shape *Parent; // The shape we are directly inside
- int Id; // A unique identifier, defined when added to relooper
+ int Id; // A unique identifier, defined when added to relooper. Note that this uniquely identifies a *logical* block - if we split it, the two instances have the same content *and* the same Id
const char *Code; // The string representation of the code in this block. Owning pointer (we copy the input)
const char *BranchVar; // If we have more than one branch out, the variable whose value determines where we go
bool IsCheckedMultipleEntry; // If true, we are a multiple entry, so reaching us requires setting the label variable
@@ -191,7 +191,7 @@ struct Relooper {
Relooper();
~Relooper();
- void AddBlock(Block *New);
+ void AddBlock(Block *New, int Id=-1);
// Calculates the shapes
void Calculate(Block *Entry);
@@ -200,11 +200,16 @@ struct Relooper {
void Render();
// Sets the global buffer all printing goes to. Must call this or MakeOutputBuffer.
+ // XXX: this is deprecated, see MakeOutputBuffer
static void SetOutputBuffer(char *Buffer, int Size);
- // Creates an output buffer. Must call this or SetOutputBuffer.
+ // Creates an internal output buffer. Must call this or SetOutputBuffer. Size is
+ // a hint for the initial size of the buffer, it can be resized later one demand.
+ // For that reason this is more recommended than SetOutputBuffer.
static void MakeOutputBuffer(int Size);
+ static char *GetOutputBuffer();
+
// Sets asm.js mode on or off (default is off)
static void SetAsmJSMode(int On);
diff --git a/src/relooper/fuzzer.py b/src/relooper/fuzzer.py
index fa47583e..18db997e 100644
--- a/src/relooper/fuzzer.py
+++ b/src/relooper/fuzzer.py
@@ -47,8 +47,18 @@ while(1) switch(label) {
int main() {
char *buffer = (char*)malloc(10*1024*1024);
+'''
+
+ if random.randint(0, 1) == 0:
+ make = False
+ fast += '''
Relooper::SetOutputBuffer(buffer, 10*1024*1024);
'''
+ else:
+ make = True
+ fast += '''
+ Relooper::MakeOutputBuffer(%d);
+''' % random.randint(1, 1024*1024*10)
for i in range(1, num):
slow += ' case %d: print(%d); state = check(); modded = state %% %d\n' % (i, i, len(branches[i])+1)
@@ -102,11 +112,11 @@ int main() {
printf("\\n\\n");
r.Render();
- puts(buffer);
+ puts(%s);
return 1;
}
-'''
+''' % ('buffer' if not make else 'Relooper::GetOutputBuffer()')
slow += '}'
diff --git a/src/relooper/test.cpp b/src/relooper/test.cpp
index 773f6ee4..b4ce669c 100644
--- a/src/relooper/test.cpp
+++ b/src/relooper/test.cpp
@@ -286,5 +286,33 @@ int main() {
puts(buffer);
}
+
+ if (1) {
+ Relooper::MakeOutputBuffer(10);
+
+ printf("\n\n-- If pattern, emulated, using MakeOutputBuffer --\n\n");
+
+ Block *b_a = new Block("// block A\n", NULL);
+ Block *b_b = new Block("// block B\n", "b_check()");
+ Block *b_c = new Block("// block C\n", NULL);
+
+ b_a->AddBranchTo(b_b, "check == 10", "atob();");
+ b_a->AddBranchTo(b_c, NULL, "atoc();");
+
+ b_b->AddBranchTo(b_c, "case 17:", "btoc();");
+ b_b->AddBranchTo(b_a, NULL, NULL);
+
+ Relooper r;
+ r.SetEmulate(true);
+ r.AddBlock(b_a);
+ r.AddBlock(b_b);
+ r.AddBlock(b_c);
+
+ r.Calculate(b_a);
+ printf("\n\n", "the_var");
+ r.Render();
+
+ puts(buffer);
+ }
}
diff --git a/src/relooper/test.txt b/src/relooper/test.txt
index 9bdd4093..82b02ad7 100644
--- a/src/relooper/test.txt
+++ b/src/relooper/test.txt
@@ -91,7 +91,7 @@
}
default: {
var $x_1 = $x_0;
- label = 8;
+ label = 7;
break L1;
}
}
@@ -106,7 +106,7 @@
}
}
}
- if (label == 8) {
+ if (label == 7) {
// code 7
}
// code 4
@@ -315,3 +315,48 @@
}
}
+
+
+-- If pattern, emulated, using MakeOutputBuffer --
+
+
+
+ label = 1;
+ L0: while(1) {
+ switch(label|0) {
+ case 3: {
+ // block C
+ break;
+ }
+ case 1: {
+ // block A
+ if (check == 10) {
+ atob();
+ label = 2;
+ continue L0;
+ } else {
+ atoc();
+ label = 3;
+ continue L0;
+ }
+ break;
+ }
+ case 2: {
+ // block B
+ switch (b_check()) {
+ case 17: {
+ btoc();
+ label = 3;
+ continue L0;
+ break;
+ }
+ default: {
+ label = 1;
+ continue L0;
+ }
+ }
+ break;
+ }
+ }
+ }
+
diff --git a/src/runtime.js b/src/runtime.js
index cd3afb4b..1fc9e026 100644
--- a/src/runtime.js
+++ b/src/runtime.js
@@ -49,7 +49,7 @@ var RuntimeGenerator = {
stackExit: function(initial, force) {
if (initial === 0 && SKIP_STACK_IN_SMALL && !force) return '';
var ret = '';
- if (SAFE_HEAP) {
+ if (SAFE_HEAP && !ASM_JS) {
ret += 'var i = sp; while ((i|0) < (STACKTOP|0)) { SAFE_HEAP_CLEAR(i|0); i = (i+1)|0 }';
}
return ret += 'STACKTOP=sp';
diff --git a/src/shell.js b/src/shell.js
index b41fbb51..84844c85 100644
--- a/src/shell.js
+++ b/src/shell.js
@@ -38,10 +38,10 @@ var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIR
if (ENVIRONMENT_IS_NODE) {
// Expose functionality in the same simple way that the shells work
// Note that we pollute the global namespace here, otherwise we break in node
- Module['print'] = function print(x) {
+ if (!Module['print']) Module['print'] = function print(x) {
process['stdout'].write(x + '\n');
};
- Module['printErr'] = function printErr(x) {
+ if (!Module['printErr']) Module['printErr'] = function printErr(x) {
process['stderr'].write(x + '\n');
};
@@ -71,7 +71,7 @@ if (ENVIRONMENT_IS_NODE) {
module['exports'] = Module;
}
else if (ENVIRONMENT_IS_SHELL) {
- Module['print'] = print;
+ if (!Module['print']) Module['print'] = print;
if (typeof printErr != 'undefined') Module['printErr'] = printErr; // not present in v8 or older sm
if (typeof read != 'undefined') {
@@ -107,16 +107,16 @@ else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
}
if (typeof console !== 'undefined') {
- Module['print'] = function print(x) {
+ if (!Module['print']) Module['print'] = function print(x) {
console.log(x);
};
- Module['printErr'] = function printErr(x) {
+ if (!Module['printErr']) Module['printErr'] = function printErr(x) {
console.log(x);
};
} else {
// Probably a worker, and without console.log. We can do very little here...
var TRY_USE_DUMP = false;
- Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
+ if (!Module['print']) Module['print'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {
dump(x);
}) : (function(x) {
// self.postMessage(x); // enable this if you want stdout to be sent as messages