aboutsummaryrefslogtreecommitdiff
path: root/src/library.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/library.js')
-rw-r--r--src/library.js3070
1 files changed, 2031 insertions, 1039 deletions
diff --git a/src/library.js b/src/library.js
index 527df4ee..5608ea1e 100644
--- a/src/library.js
+++ b/src/library.js
@@ -15,16 +15,18 @@
// object. For convenience, the short name appears here. Note that if you add a
// new function with an '_', it will not be found.
+// Memory allocated during startup, in postsets, should only be ALLOC_STATIC
+
LibraryManager.library = {
// ==========================================================================
// File system base.
// ==========================================================================
// keep this low in memory, because we flatten arrays with them in them
- stdin: 'allocate(1, "i32*", ALLOC_STACK)',
- stdout: 'allocate(1, "i32*", ALLOC_STACK)',
- stderr: 'allocate(1, "i32*", ALLOC_STACK)',
- _impure_ptr: 'allocate(1, "i32*", ALLOC_STACK)',
+ stdin: 'allocate(1, "i32*", ALLOC_STATIC)',
+ stdout: 'allocate(1, "i32*", ALLOC_STATIC)',
+ stderr: 'allocate(1, "i32*", ALLOC_STATIC)',
+ _impure_ptr: 'allocate(1, "i32*", ALLOC_STATIC)',
$FS__deps: ['$ERRNO_CODES', '__setErrNo', 'stdin', 'stdout', 'stderr', '_impure_ptr'],
$FS__postset: '__ATINIT__.unshift({ func: function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() } });' +
@@ -52,7 +54,7 @@ LibraryManager.library = {
streams: [null],
#if ASSERTIONS
checkStreams: function() {
- for (var i in FS.streams) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
+ for (var i in FS.streams) if (FS.streams.hasOwnProperty(i)) assert(i >= 0 && i < FS.streams.length); // no keys not in dense span
for (var i = 0; i < FS.streams.length; i++) assert(typeof FS.streams[i] == 'object'); // no non-null holes in dense span
},
#endif
@@ -65,7 +67,6 @@ LibraryManager.library = {
if (typeof stream === 'undefined') {
stream = null;
}
- // Keep dense
fd = (typeof fd !== 'undefined') ? fd : FS.streams.length;
for (var i = FS.streams.length; i < fd; i++) {
FS.streams[i] = null; // Keep dense
@@ -271,7 +272,7 @@ LibraryManager.library = {
var properties = {isFolder: true, isDevice: false, contents: {}};
return FS.createObject(parent, name, properties, canRead, canWrite);
},
- // Creates a a folder and all its missing parents.
+ // Creates a folder and all its missing parents.
createPath: function(parent, path, canRead, canWrite) {
var current = FS.findObject(parent);
if (current === null) throw new Error('Invalid parent.');
@@ -313,74 +314,98 @@ LibraryManager.library = {
if (typeof XMLHttpRequest !== 'undefined') {
if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
// Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
- var LazyUint8Array = function(chunkSize, length) {
- this.length = length;
- this.chunkSize = chunkSize;
+ var LazyUint8Array = function() {
+ this.lengthKnown = false;
this.chunks = []; // Loaded chunks. Index is the chunk number
}
LazyUint8Array.prototype.get = function(idx) {
if (idx > this.length-1 || idx < 0) {
return undefined;
}
- var chunkOffset = idx % chunkSize;
- var chunkNum = Math.floor(idx / chunkSize);
+ var chunkOffset = idx % this.chunkSize;
+ var chunkNum = Math.floor(idx / this.chunkSize);
return this.getter(chunkNum)[chunkOffset];
}
LazyUint8Array.prototype.setDataGetter = function(getter) {
this.getter = getter;
}
-
- // Find length
- var xhr = new XMLHttpRequest();
- xhr.open('HEAD', url, false);
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- var datalength = Number(xhr.getResponseHeader("Content-length"));
- var header;
- var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
+
+ LazyUint8Array.prototype.cacheLength = function() {
+ // Find length
+ var xhr = new XMLHttpRequest();
+ xhr.open('HEAD', url, false);
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ var datalength = Number(xhr.getResponseHeader("Content-length"));
+ var header;
+ var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
#if SMALL_XHR_CHUNKS
- var chunkSize = 1024; // Chunk size in bytes
+ var chunkSize = 1024; // Chunk size in bytes
#else
- var chunkSize = 1024*1024; // Chunk size in bytes
+ var chunkSize = 1024*1024; // Chunk size in bytes
#endif
- if (!hasByteServing) chunkSize = datalength;
-
- // Function to get a range from the remote URL.
- var doXHR = (function(from, to) {
- if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
- if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
-
- // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, false);
- if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
-
- // Some hints to the browser that we want binary data.
- if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
- if (xhr.overrideMimeType) {
- xhr.overrideMimeType('text/plain; charset=x-user-defined');
- }
-
- xhr.send(null);
- if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
- if (xhr.response !== undefined) {
- return new Uint8Array(xhr.response || []);
- } else {
- return intArrayFromString(xhr.responseText || '', true);
- }
+
+ if (!hasByteServing) chunkSize = datalength;
+
+ // Function to get a range from the remote URL.
+ var doXHR = (function(from, to) {
+ if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
+ if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
+
+ // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url, false);
+ if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
+
+ // Some hints to the browser that we want binary data.
+ if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
+ if (xhr.overrideMimeType) {
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+
+ xhr.send(null);
+ if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
+ if (xhr.response !== undefined) {
+ return new Uint8Array(xhr.response || []);
+ } else {
+ return intArrayFromString(xhr.responseText || '', true);
+ }
+ });
+ var lazyArray = this;
+ lazyArray.setDataGetter(function(chunkNum) {
+ var start = chunkNum * chunkSize;
+ var end = (chunkNum+1) * chunkSize - 1; // including this byte
+ end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
+ lazyArray.chunks[chunkNum] = doXHR(start, end);
+ }
+ if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
+ return lazyArray.chunks[chunkNum];
+ });
+
+ this._length = datalength;
+ this._chunkSize = chunkSize;
+ this.lengthKnown = true;
+ }
+
+ var lazyArray = new LazyUint8Array();
+ Object.defineProperty(lazyArray, "length", {
+ get: function() {
+ if(!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._length;
+ }
});
-
- var lazyArray = new LazyUint8Array(chunkSize, datalength);
- lazyArray.setDataGetter(function(chunkNum) {
- var start = chunkNum * lazyArray.chunkSize;
- var end = (chunkNum+1) * lazyArray.chunkSize - 1; // including this byte
- end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
- lazyArray.chunks[chunkNum] = doXHR(start, end);
- }
- if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
- return lazyArray.chunks[chunkNum];
+ Object.defineProperty(lazyArray, "chunkSize", {
+ get: function() {
+ if(!this.lengthKnown) {
+ this.cacheLength();
+ }
+ return this._chunkSize;
+ }
});
+
var properties = { isDevice: false, contents: lazyArray };
} else {
var properties = { isDevice: false, url: url };
@@ -401,7 +426,7 @@ LibraryManager.library = {
// do preloading for the Image/Audio part, as if the typed array were the
// result of an XHR that you did manually.
createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile) {
- Browser.ensureObjects();
+ Browser.init();
var fullname = FS.joinPath([parent, name], true);
function processData(byteArray) {
function finish(byteArray) {
@@ -433,7 +458,7 @@ LibraryManager.library = {
processData(url);
}
},
- // Creates a link to a sepcific local path.
+ // Creates a link to a specific local path.
createLink: function(parent, name, target, canRead, canWrite) {
var properties = {isDevice: false, link: target};
return FS.createFile(parent, name, properties, canRead, canWrite);
@@ -523,7 +548,7 @@ LibraryManager.library = {
}
var utf8 = new Runtime.UTF8Processor();
function simpleOutput(val) {
- if (val === null || val === '\n'.charCodeAt(0)) {
+ if (val === null || val === {{{ charCode('\n') }}}) {
output.printer(output.buffer.join(''));
output.buffer = [];
} else {
@@ -554,6 +579,7 @@ LibraryManager.library = {
var stdout = FS.createDevice(devFolder, 'stdout', null, output);
var stderr = FS.createDevice(devFolder, 'stderr', null, error);
FS.createDevice(devFolder, 'tty', input, output);
+ FS.createDevice(devFolder, 'null', function(){}, function(){});
// Create default streams.
FS.streams[1] = {
@@ -592,7 +618,7 @@ LibraryManager.library = {
eof: false,
ungotten: []
};
- assert(Math.max(_stdin, _stdout, _stderr) < 128); // make sure these are low, we flatten arrays with these
+ // TODO: put these low in memory like we used to assert on: assert(Math.max(_stdin, _stdout, _stderr) < 15000); // make sure these are low, we flatten arrays with these
{{{ makeSetValue(makeGlobalUse('_stdin'), 0, 1, 'void*') }}};
{{{ makeSetValue(makeGlobalUse('_stdout'), 0, 2, 'void*') }}};
{{{ makeSetValue(makeGlobalUse('_stderr'), 0, 3, 'void*') }}};
@@ -609,18 +635,18 @@ LibraryManager.library = {
FS.streams[_stderr] = FS.streams[3];
#if ASSERTIONS
FS.checkStreams();
- assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
+ // see previous TODO on stdin etc.: assert(FS.streams.length < 1024); // at this early stage, we should not have a large set of file descriptors - just a few
#endif
allocate([ allocate(
{{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}},
- 'void*', ALLOC_STATIC) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}});
+ 'void*', ALLOC_NORMAL) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}});
},
quit: function() {
if (!FS.init.initialized) return;
// Flush any partially-printed lines in stdout and stderr. Careful, they may have been closed
- if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output('\n'.charCodeAt(0));
- if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output('\n'.charCodeAt(0));
+ if (FS.streams[2] && FS.streams[2].object.output.buffer.length > 0) FS.streams[2].object.output({{{ charCode('\n') }}});
+ if (FS.streams[3] && FS.streams[3].object.output.buffer.length > 0) FS.streams[3].object.output({{{ charCode('\n') }}});
},
// Standardizes a path. Useful for making comparisons of pathnames work in a consistent manner.
@@ -643,7 +669,12 @@ LibraryManager.library = {
// dirent.h
// ==========================================================================
- __dirent_struct_layout: Runtime.generateStructInfo(['d_ino', 'd_name', 'd_off', 'd_reclen', 'd_type'], '%struct.dirent'),
+ __dirent_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'd_ino'],
+ ['b1024', 'd_name'],
+ ['i32', 'd_off'],
+ ['i32', 'd_reclen'],
+ ['i32', 'd_type']]),
opendir__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
opendir: function(dirname) {
// DIR *opendir(const char *dirname);
@@ -804,7 +835,9 @@ LibraryManager.library = {
// utime.h
// ==========================================================================
- __utimbuf_struct_layout: Runtime.generateStructInfo(['actime', 'modtime'], '%struct.utimbuf'),
+ __utimbuf_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'actime'],
+ ['i32', 'modtime']]),
utime__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__utimbuf_struct_layout'],
utime: function(path, times) {
// int utime(const char *path, const struct utimbuf *times);
@@ -828,6 +861,8 @@ LibraryManager.library = {
return 0;
},
+ utimes: function() { throw 'utimes not implemented' },
+
// ==========================================================================
// libgen.h
// ==========================================================================
@@ -837,11 +872,11 @@ LibraryManager.library = {
// Null or empty results in '.'.
var me = ___libgenSplitName;
if (!me.ret) {
- me.ret = allocate(['.'.charCodeAt(0), 0], 'i8', ALLOC_NORMAL);
+ me.ret = allocate([{{{ charCode('.') }}}, 0], 'i8', ALLOC_NORMAL);
}
return [me.ret, -1];
} else {
- var slash = '/'.charCodeAt(0);
+ var slash = {{{ charCode('/') }}};
var allSlashes = true;
var slashPositions = [];
for (var i = 0; {{{ makeGetValue('path', 'i', 'i8') }}} !== 0; i++) {
@@ -893,23 +928,23 @@ LibraryManager.library = {
// ==========================================================================
__stat_struct_layout: Runtime.generateStructInfo([
- 'st_dev',
- 'st_ino',
- 'st_mode',
- 'st_nlink',
- 'st_uid',
- 'st_gid',
- 'st_rdev',
- 'st_size',
- 'st_atime',
- 'st_spare1',
- 'st_mtime',
- 'st_spare2',
- 'st_ctime',
- 'st_spare3',
- 'st_blksize',
- 'st_blocks',
- 'st_spare4'], '%struct.stat'),
+ ['i32', 'st_dev'],
+ ['i32', 'st_ino'],
+ ['i32', 'st_mode'],
+ ['i32', 'st_nlink'],
+ ['i32', 'st_uid'],
+ ['i32', 'st_gid'],
+ ['i32', 'st_rdev'],
+ ['i32', 'st_size'],
+ ['i32', 'st_atime'],
+ ['i32', 'st_spare1'],
+ ['i32', 'st_mtime'],
+ ['i32', 'st_spare2'],
+ ['i32', 'st_ctime'],
+ ['i32', 'st_spare3'],
+ ['i32', 'st_blksize'],
+ ['i32', 'st_blocks'],
+ ['i32', 'st_spare4']]),
stat__deps: ['$FS', '__stat_struct_layout'],
stat: function(path, buf, dontResolveLastLink) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -1056,6 +1091,8 @@ LibraryManager.library = {
return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode);
}
},
+ lchmod: function() { throw 'TODO: lchmod' },
+
umask__deps: ['$FS'],
umask: function(newMask) {
// mode_t umask(mode_t cmask);
@@ -1079,17 +1116,17 @@ LibraryManager.library = {
// ==========================================================================
__statvfs_struct_layout: Runtime.generateStructInfo([
- 'f_bsize',
- 'f_frsize',
- 'f_blocks',
- 'f_bfree',
- 'f_bavail',
- 'f_files',
- 'f_ffree',
- 'f_favail',
- 'f_fsid',
- 'f_flag',
- 'f_namemax'], '%struct.statvfs'),
+ ['i32', 'f_bsize'],
+ ['i32', 'f_frsize'],
+ ['i32', 'f_blocks'],
+ ['i32', 'f_bfree'],
+ ['i32', 'f_bavail'],
+ ['i32', 'f_files'],
+ ['i32', 'f_ffree'],
+ ['i32', 'f_favail'],
+ ['i32', 'f_fsid'],
+ ['i32', 'f_flag'],
+ ['i32', 'f_namemax']]),
statvfs__deps: ['$FS', '__statvfs_struct_layout'],
statvfs: function(path, buf) {
// http://pubs.opengroup.org/onlinepubs/7908799/xsh/stat.html
@@ -1124,17 +1161,17 @@ LibraryManager.library = {
// ==========================================================================
__flock_struct_layout: Runtime.generateStructInfo([
- 'l_type',
- 'l_whence',
- 'l_start',
- 'l_len',
- 'l_pid',
- 'l_xxx'], '%struct.flock'),
+ ['i16', 'l_type'],
+ ['i16', 'l_whence'],
+ ['i32', 'l_start'],
+ ['i32', 'l_len'],
+ ['i16', 'l_pid'],
+ ['i16', 'l_xxx']]),
open__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', '__dirent_struct_layout'],
open: function(path, oflag, varargs) {
// int open(const char *path, int oflag, ...);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/open.html
- // NOTE: This implementation tries to mimic glibc rather that strictly
+ // NOTE: This implementation tries to mimic glibc rather than strictly
// following the POSIX standard.
var mode = {{{ makeGetValue('varargs', 0, 'i32') }}};
@@ -1347,12 +1384,15 @@ LibraryManager.library = {
// poll.h
// ==========================================================================
- __pollfd_struct_layout: Runtime.generateStructInfo(['fd', 'events', 'revents'], '%struct.pollfd'),
+ __pollfd_struct_layout: Runtime.generateStructInfo([
+ ['i32', 'fd'],
+ ['i16', 'events'],
+ ['i16', 'revents']]),
poll__deps: ['$FS', '__pollfd_struct_layout'],
poll: function(fds, nfds, timeout) {
// int poll(struct pollfd fds[], nfds_t nfds, int timeout);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.html
- // NOTE: This is pretty much a no-op mimicing glibc.
+ // NOTE: This is pretty much a no-op mimicking glibc.
var offsets = ___pollfd_struct_layout;
var nonzero = 0;
for (var i = 0; i < nfds; i++) {
@@ -1516,7 +1556,7 @@ LibraryManager.library = {
// long fpathconf(int fildes, int name);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/encrypt.html
// NOTE: The first parameter is ignored, so pathconf == fpathconf.
- // The constants here aren't real values. Just mimicing glibc.
+ // The constants here aren't real values. Just mimicking glibc.
switch (name) {
case {{{ cDefine('_PC_LINK_MAX') }}}:
return 32000;
@@ -1731,7 +1771,12 @@ LibraryManager.library = {
}
var contents = stream.object.contents;
var size = Math.min(contents.length - offset, nbyte);
- if (contents.subarray || contents.slice) { // typed array or normal array
+#if USE_TYPED_ARRAYS == 2
+ if (contents.subarray) { // typed array
+ HEAPU8.set(contents.subarray(offset, offset+size), buf);
+ } else
+#endif
+ if (contents.slice) { // normal array
for (var i = 0; i < size; i++) {
{{{ makeSetValue('buf', 'i', 'contents[offset + i]', 'i8') }}}
}
@@ -2061,24 +2106,19 @@ LibraryManager.library = {
// void _exit(int status);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
-#if CATCH_EXIT_CODE
function ExitStatus() {
this.name = "ExitStatus";
this.message = "Program terminated with exit(" + status + ")";
this.status = status;
+ Module.print('Exit Status: ' + status);
};
ExitStatus.prototype = new Error();
ExitStatus.prototype.constructor = ExitStatus;
-#endif
exitRuntime();
ABORT = true;
-#if CATCH_EXIT_CODE
throw new ExitStatus();
-#else
- throw 'exit(' + status + ') called, at ' + new Error().stack;
-#endif
},
fork__deps: ['__setErrNo', '$ERRNO_CODES'],
fork: function() {
@@ -2123,7 +2163,20 @@ LibraryManager.library = {
return 1;
}
},
- // TODO: Implement initgroups, setgroups (grp.h).
+ // TODO: Implement initgroups (grp.h).
+ setgroups__deps: ['__setErrNo', '$ERRNO_CODES', 'sysconf'],
+ setgroups: function (ngroups, gidset) {
+ // int setgroups(int ngroups, const gid_t *gidset);
+ // https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man2/setgroups.2.html
+ if (ngroups < 1 || ngroups > _sysconf({{{ cDefine('_SC_NGROUPS_MAX') }}})) {
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
+ } else {
+ // We have just one process/user/group, so it makes no sense to set groups.
+ ___setErrNo(ERRNO_CODES.EPERM);
+ return -1;
+ }
+ },
gethostid: function() {
// long gethostid(void);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/gethostid.html
@@ -2408,6 +2461,7 @@ LibraryManager.library = {
case {{{ cDefine('_SC_STREAM_MAX') }}}: return 16;
case {{{ cDefine('_SC_TZNAME_MAX') }}}: return 6;
case {{{ cDefine('_SC_THREAD_DESTRUCTOR_ITERATIONS') }}}: return 4;
+ case {{{ cDefine('_SC_NPROCESSORS_ONLN') }}}: return 1;
}
___setErrNo(ERRNO_CODES.EINVAL);
return -1;
@@ -2416,22 +2470,17 @@ LibraryManager.library = {
// Implement a Linux-like 'memory area' for our 'process'.
// Changes the size of the memory area by |bytes|; returns the
// address of the previous top ('break') of the memory area
-
- // We need to make sure no one else allocates unfreeable memory!
- // We must control this entirely. So we don't even need to do
- // unfreeable allocations - the HEAP is ours, from STATICTOP up.
- // TODO: We could in theory slice off the top of the HEAP when
- // sbrk gets a negative increment in |bytes|...
+ // We control the "dynamic" memory - DYNAMIC_BASE to DYNAMICTOP
var self = _sbrk;
if (!self.called) {
- STATICTOP = alignMemoryPage(STATICTOP); // make sure we start out aligned
+ DYNAMICTOP = alignMemoryPage(DYNAMICTOP); // make sure we start out aligned
self.called = true;
-#if GC_SUPPORT
- _sbrk.DYNAMIC_START = STATICTOP;
-#endif
+ assert(Runtime.dynamicAlloc);
+ self.alloc = Runtime.dynamicAlloc;
+ Runtime.dynamicAlloc = function() { abort('cannot dynamically allocate, sbrk now has control') };
}
- var ret = STATICTOP;
- if (bytes != 0) Runtime.staticAlloc(bytes);
+ var ret = DYNAMICTOP;
+ if (bytes != 0) self.alloc(bytes);
return ret; // Previous break location.
},
open64: 'open',
@@ -2456,12 +2505,18 @@ LibraryManager.library = {
_scanString: function(format, get, unget, varargs) {
if (!__scanString.whiteSpace) {
__scanString.whiteSpace = {};
- __scanString.whiteSpace[' '.charCodeAt(0)] = 1;
- __scanString.whiteSpace['\t'.charCodeAt(0)] = 1;
- __scanString.whiteSpace['\n'.charCodeAt(0)] = 1;
+ __scanString.whiteSpace[{{{ charCode(' ') }}}] = 1;
+ __scanString.whiteSpace[{{{ charCode('\t') }}}] = 1;
+ __scanString.whiteSpace[{{{ charCode('\n') }}}] = 1;
+ __scanString.whiteSpace[{{{ charCode('\v') }}}] = 1;
+ __scanString.whiteSpace[{{{ charCode('\f') }}}] = 1;
+ __scanString.whiteSpace[{{{ charCode('\r') }}}] = 1;
__scanString.whiteSpace[' '] = 1;
__scanString.whiteSpace['\t'] = 1;
__scanString.whiteSpace['\n'] = 1;
+ __scanString.whiteSpace['\v'] = 1;
+ __scanString.whiteSpace['\f'] = 1;
+ __scanString.whiteSpace['\r'] = 1;
}
// Supports %x, %4x, %d.%d, %lld, %s, %f, %lf.
// TODO: Support all format specifiers.
@@ -2490,12 +2545,23 @@ LibraryManager.library = {
for (var formatIndex = 0; formatIndex < format.length;) {
if (format[formatIndex] === '%' && format[formatIndex+1] == 'n') {
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
- argIndex += Runtime.getNativeFieldSize('void*');
+ argIndex += Runtime.getAlignSize('void*', null, true);
{{{ makeSetValue('argPtr', 0, 'soFar', 'i32') }}};
formatIndex += 2;
continue;
}
+ // TODO: Support strings like "%5c" etc.
+ if (format[formatIndex] === '%' && format[formatIndex+1] == 'c') {
+ var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
+ argIndex += Runtime.getAlignSize('void*', null, true);
+ fields++;
+ next = get();
+ {{{ makeSetValue('argPtr', 0, 'next', 'i8') }}}
+ formatIndex += 2;
+ continue;
+ }
+
// remove whitespace
while (1) {
next = get();
@@ -2506,9 +2572,14 @@ LibraryManager.library = {
if (format[formatIndex] === '%') {
formatIndex++;
+ var suppressAssignment = false;
+ if (format[formatIndex] == '*') {
+ suppressAssignment = true;
+ formatIndex++;
+ }
var maxSpecifierStart = formatIndex;
- while (format[formatIndex].charCodeAt(0) >= '0'.charCodeAt(0) &&
- format[formatIndex].charCodeAt(0) <= '9'.charCodeAt(0)) {
+ while (format[formatIndex].charCodeAt(0) >= {{{ charCode('0') }}} &&
+ format[formatIndex].charCodeAt(0) <= {{{ charCode('9') }}}) {
formatIndex++;
}
var max_;
@@ -2521,7 +2592,7 @@ LibraryManager.library = {
if (format[formatIndex] == 'l') {
long_ = true;
formatIndex++;
- if(format[formatIndex] == 'l') {
+ if (format[formatIndex] == 'l') {
longLong = true;
formatIndex++;
}
@@ -2534,7 +2605,7 @@ LibraryManager.library = {
var curr = 0;
var buffer = [];
// Read characters according to the format. floats are trickier, they may be in an unfloat state in the middle, then be a valid float later
- if (type == 'f') {
+ if (type == 'f' || type == 'e' || type == 'g' || type == 'E') {
var last = 0;
next = get();
while (next > 0) {
@@ -2554,11 +2625,11 @@ LibraryManager.library = {
while ((curr < max_ || isNaN(max_)) && next > 0) {
if (!(next in __scanString.whiteSpace) && // stop on whitespace
(type == 's' ||
- ((type === 'd' || type == 'u' || type == 'i') && ((next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) ||
- (first && next == '-'.charCodeAt(0)))) ||
- (type === 'x' && (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0) ||
- next >= 'a'.charCodeAt(0) && next <= 'f'.charCodeAt(0) ||
- next >= 'A'.charCodeAt(0) && next <= 'F'.charCodeAt(0)))) &&
+ ((type === 'd' || type == 'u' || type == 'i') && ((next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) ||
+ (first && next == {{{ charCode('-') }}}))) ||
+ (type === 'x' && (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}} ||
+ next >= {{{ charCode('a') }}} && next <= {{{ charCode('f') }}} ||
+ next >= {{{ charCode('A') }}} && next <= {{{ charCode('F') }}}))) &&
(formatIndex >= format.length || next !== format[formatIndex].charCodeAt(0))) { // Stop when we read something that is coming up
buffer.push(String.fromCharCode(next));
next = get();
@@ -2571,14 +2642,16 @@ LibraryManager.library = {
unget();
}
if (buffer.length === 0) return 0; // Failure.
+ if (suppressAssignment) continue;
+
var text = buffer.join('');
var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}};
- argIndex += Runtime.getNativeFieldSize('void*');
+ argIndex += Runtime.getAlignSize('void*', null, true);
switch (type) {
case 'd': case 'u': case 'i':
if (half) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}};
- } else if(longLong) {
+ } else if (longLong) {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i64') }}};
} else {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}};
@@ -2588,6 +2661,10 @@ LibraryManager.library = {
{{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}
break;
case 'f':
+ case 'e':
+ case 'g':
+ case 'E':
+ // fallthrough intended
if (long_) {
{{{ makeSetValue('argPtr', 0, 'parseFloat(text)', 'double') }}}
} else {
@@ -2622,10 +2699,11 @@ LibraryManager.library = {
}
return fields;
},
- // Performs prtinf-style formatting.
+ // Performs printf-style formatting.
// format: A pointer to the format string.
// varargs: A pointer to the start of the arguments list.
// Returns the resulting string string as a character array.
+ _formatString__deps: ['strlen', '_reallyNegative'],
_formatString: function(format, varargs) {
var textIndex = format;
var argIndex = 0;
@@ -2637,8 +2715,16 @@ LibraryManager.library = {
ret = {{{ makeGetValue('varargs', 'argIndex', 'double', undefined, undefined, true) }}};
#if USE_TYPED_ARRAYS == 2
} else if (type == 'i64') {
+
+#if TARGET_LE32
+ ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
+ {{{ makeGetValue('varargs', 'argIndex+8', 'i32', undefined, undefined, true) }}}];
+ argIndex += {{{ STACK_ALIGN }}}; // each 32-bit chunk is in a 64-bit block
+#else
ret = [{{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}},
{{{ makeGetValue('varargs', 'argIndex+4', 'i32', undefined, undefined, true) }}}];
+#endif
+
#else
} else if (type == 'i64') {
ret = {{{ makeGetValue('varargs', 'argIndex', 'i64', undefined, undefined, true) }}};
@@ -2647,7 +2733,7 @@ LibraryManager.library = {
type = 'i32'; // varargs are always i32, i64, or double
ret = {{{ makeGetValue('varargs', 'argIndex', 'i32', undefined, undefined, true) }}};
}
- argIndex += Runtime.getNativeFieldSize(type);
+ argIndex += Math.max(Runtime.getNativeFieldSize(type), Runtime.getAlignSize(type, null, true));
return ret;
}
@@ -2658,7 +2744,7 @@ LibraryManager.library = {
curr = {{{ makeGetValue(0, 'textIndex', 'i8') }}};
if (curr === 0) break;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
- if (curr == '%'.charCodeAt(0)) {
+ if (curr == {{{ charCode('%') }}}) {
// Handle flags.
var flagAlwaysSigned = false;
var flagLeftAlign = false;
@@ -2666,16 +2752,16 @@ LibraryManager.library = {
var flagZeroPad = false;
flagsLoop: while (1) {
switch (next) {
- case '+'.charCodeAt(0):
+ case {{{ charCode('+') }}}:
flagAlwaysSigned = true;
break;
- case '-'.charCodeAt(0):
+ case {{{ charCode('-') }}}:
flagLeftAlign = true;
break;
- case '#'.charCodeAt(0):
+ case {{{ charCode('#') }}}:
flagAlternative = true;
break;
- case '0'.charCodeAt(0):
+ case {{{ charCode('0') }}}:
if (flagZeroPad) {
break flagsLoop;
} else {
@@ -2691,13 +2777,13 @@ LibraryManager.library = {
// Handle width.
var width = 0;
- if (next == '*'.charCodeAt(0)) {
+ if (next == {{{ charCode('*') }}}) {
width = getNextArg('i32');
textIndex++;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
} else {
- while (next >= '0'.charCodeAt(0) && next <= '9'.charCodeAt(0)) {
- width = width * 10 + (next - '0'.charCodeAt(0));
+ while (next >= {{{ charCode('0') }}} && next <= {{{ charCode('9') }}}) {
+ width = width * 10 + (next - {{{ charCode('0') }}});
textIndex++;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
}
@@ -2705,20 +2791,20 @@ LibraryManager.library = {
// Handle precision.
var precisionSet = false;
- if (next == '.'.charCodeAt(0)) {
+ if (next == {{{ charCode('.') }}}) {
var precision = 0;
precisionSet = true;
textIndex++;
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
- if (next == '*'.charCodeAt(0)) {
+ if (next == {{{ charCode('*') }}}) {
precision = getNextArg('i32');
textIndex++;
} else {
while(1) {
var precisionChr = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
- if (precisionChr < '0'.charCodeAt(0) ||
- precisionChr > '9'.charCodeAt(0)) break;
- precision = precision * 10 + (precisionChr - '0'.charCodeAt(0));
+ if (precisionChr < {{{ charCode('0') }}} ||
+ precisionChr > {{{ charCode('9') }}}) break;
+ precision = precision * 10 + (precisionChr - {{{ charCode('0') }}});
textIndex++;
}
}
@@ -2732,7 +2818,7 @@ LibraryManager.library = {
switch (String.fromCharCode(next)) {
case 'h':
var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
- if (nextNext == 'h'.charCodeAt(0)) {
+ if (nextNext == {{{ charCode('h') }}}) {
textIndex++;
argSize = 1; // char (actually i32 in varargs)
} else {
@@ -2741,7 +2827,7 @@ LibraryManager.library = {
break;
case 'l':
var nextNext = {{{ makeGetValue(0, 'textIndex+2', 'i8') }}};
- if (nextNext == 'l'.charCodeAt(0)) {
+ if (nextNext == {{{ charCode('l') }}}) {
textIndex++;
argSize = 8; // long long
} else {
@@ -2765,226 +2851,255 @@ LibraryManager.library = {
next = {{{ makeGetValue(0, 'textIndex+1', 'i8') }}};
// Handle type specifier.
- if (['d', 'i', 'u', 'o', 'x', 'X', 'p'].indexOf(String.fromCharCode(next)) != -1) {
- // Integer.
- var signed = next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0);
- argSize = argSize || 4;
- var currArg = getNextArg('i' + (argSize * 8));
+ switch (String.fromCharCode(next)) {
+ case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'p': {
+ // Integer.
+ var signed = next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}};
+ argSize = argSize || 4;
+ var currArg = getNextArg('i' + (argSize * 8));
#if PRECISE_I64_MATH
- var origArg = currArg;
+ var origArg = currArg;
#endif
- var argText;
+ var argText;
#if USE_TYPED_ARRAYS == 2
- // Flatten i64-1 [low, high] into a (slightly rounded) double
- if (argSize == 8) {
- currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == 'u'.charCodeAt(0));
- }
+ // Flatten i64-1 [low, high] into a (slightly rounded) double
+ if (argSize == 8) {
+ currArg = Runtime.makeBigInt(currArg[0], currArg[1], next == {{{ charCode('u') }}});
+ }
#endif
- // Truncate to requested size.
- if (argSize <= 4) {
- var limit = Math.pow(256, argSize) - 1;
- currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
- }
- // Format the number.
- var currAbsArg = Math.abs(currArg);
- var prefix = '';
- if (next == 'd'.charCodeAt(0) || next == 'i'.charCodeAt(0)) {
+ // Truncate to requested size.
+ if (argSize <= 4) {
+ var limit = Math.pow(256, argSize) - 1;
+ currArg = (signed ? reSign : unSign)(currArg & limit, argSize * 8);
+ }
+ // Format the number.
+ var currAbsArg = Math.abs(currArg);
+ var prefix = '';
+ if (next == {{{ charCode('d') }}} || next == {{{ charCode('i') }}}) {
#if PRECISE_I64_MATH
- if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
+ if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], null); else
#endif
- argText = reSign(currArg, 8 * argSize, 1).toString(10);
- } else if (next == 'u'.charCodeAt(0)) {
+ argText = reSign(currArg, 8 * argSize, 1).toString(10);
+ } else if (next == {{{ charCode('u') }}}) {
#if PRECISE_I64_MATH
- if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
+ if (argSize == 8 && i64Math) argText = i64Math.stringify(origArg[0], origArg[1], true); else
#endif
- argText = unSign(currArg, 8 * argSize, 1).toString(10);
- currArg = Math.abs(currArg);
- } else if (next == 'o'.charCodeAt(0)) {
- argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
- } else if (next == 'x'.charCodeAt(0) || next == 'X'.charCodeAt(0)) {
- prefix = flagAlternative ? '0x' : '';
+ argText = unSign(currArg, 8 * argSize, 1).toString(10);
+ currArg = Math.abs(currArg);
+ } else if (next == {{{ charCode('o') }}}) {
+ argText = (flagAlternative ? '0' : '') + currAbsArg.toString(8);
+ } else if (next == {{{ charCode('x') }}} || next == {{{ charCode('X') }}}) {
+ prefix = (flagAlternative && currArg != 0) ? '0x' : '';
#if PRECISE_I64_MATH<