aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js8
-rw-r--r--src/jsifier.js18
-rw-r--r--src/library.js38
-rw-r--r--src/library_browser.js22
-rw-r--r--src/library_fs.js90
-rw-r--r--src/library_memfs.js6
-rw-r--r--src/library_path.js3
-rw-r--r--src/library_sdl.js26
-rw-r--r--src/library_tty.js41
-rw-r--r--src/parseTools.js2
-rw-r--r--src/settings.js6
11 files changed, 224 insertions, 36 deletions
diff --git a/src/analyzer.js b/src/analyzer.js
index 2a7d64f5..b20dedff 100644
--- a/src/analyzer.js
+++ b/src/analyzer.js
@@ -281,6 +281,14 @@ function analyzer(data, sidePass) {
Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
i += toAdd.length;
continue;
+ } else if (param.intertype == 'structvalue') {
+ // 'flatten' out the struct into scalars
+ var toAdd = param.params;
+ toAdd.forEach(function(param) {
+ param.byval = 0;
+ });
+ Array.prototype.splice.apply(params, [i, 1].concat(toAdd));
+ continue; // do not increment i; proceed to process the new params
}
i++;
}
diff --git a/src/jsifier.js b/src/jsifier.js
index 179a910a..7273f54c 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -23,7 +23,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var mainPass = !functionsOnly;
if (mainPass) {
- var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB ? 'shell_sharedlib.js' : 'shell.js');
+ var shellFile = SHELL_FILE ? SHELL_FILE : (BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'shell_sharedlib.js' : 'shell.js');
if (phase == 'pre') {
// We will start to print out the data, but must do so carefully - we are
@@ -47,10 +47,11 @@ function JSify(data, functionsOnly, givenFunctions) {
var shellParts = read(shellFile).split('{{BODY}}');
print(processMacros(preprocess(shellParts[0])));
- var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
+ var preFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'preamble_sharedlib.js' : 'preamble.js';
var pre = processMacros(preprocess(read(preFile).replace('{{RUNTIME}}', getRuntime())));
print(pre);
+ // Populate implementedFunctions. Note that this is before types, and will be updated later.
data.unparsedFunctions.forEach(function(func) {
Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
});
@@ -80,7 +81,7 @@ function JSify(data, functionsOnly, givenFunctions) {
if (phase == 'pre') {
var libFuncsToInclude;
if (INCLUDE_FULL_LIBRARY) {
- assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
+ assert(!(BUILD_AS_SHARED_LIB || SIDE_MODULE), 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB/SIDE_MODULE set.')
libFuncsToInclude = [];
for (var key in LibraryManager.library) {
if (!key.match(/__(deps|postset|inline|asm|sig)$/)) {
@@ -454,7 +455,7 @@ function JSify(data, functionsOnly, givenFunctions) {
var postsetId = ident + '__postset';
var postset = LibraryManager.library[postsetId];
- if (postset && !addedLibraryItems[postsetId]) {
+ if (postset && !addedLibraryItems[postsetId] && !SIDE_MODULE) {
addedLibraryItems[postsetId] = true;
ret.push({
intertype: 'GlobalVariablePostSet',
@@ -497,6 +498,7 @@ function JSify(data, functionsOnly, givenFunctions) {
Functions.libraryFunctions[ident.substr(1)] = 2;
}
}
+ if (SIDE_MODULE) return ';'; // we import into the side module js library stuff from the outside parent
if ((!ASM_JS || phase == 'pre') &&
(EXPORT_ALL || (ident in EXPORTED_FUNCTIONS))) {
contentText += '\nModule["' + ident + '"] = ' + ident + ';';
@@ -1835,7 +1837,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
print('Runtime.structMetadata = ' + JSON.stringify(Types.structMetadata));
}
- var postFile = BUILD_AS_SHARED_LIB ? 'postamble_sharedlib.js' : 'postamble.js';
+ var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js';
var postParts = processMacros(preprocess(read(postFile))).split('{{GLOBAL_VARS}}');
print(postParts[0]);
@@ -1871,6 +1873,12 @@ function JSify(data, functionsOnly, givenFunctions) {
// Data
if (mainPass) {
+ if (phase == 'pre') {
+ // types have been parsed, so we can figure out function signatures (which can use types)
+ data.unparsedFunctions.forEach(function(func) {
+ Functions.implementedFunctions[func.ident] = Functions.getSignature(func.returnType, func.params.map(function(param) { return param.type }));
+ });
+ }
substrate.addItems(data.functionStubs, 'FunctionStub');
assert(data.functions.length == 0);
} else {
diff --git a/src/library.js b/src/library.js
index 3ba2f56b..f6b3d5ef 100644
--- a/src/library.js
+++ b/src/library.js
@@ -2261,7 +2261,11 @@ LibraryManager.library = {
// void clearerr(FILE *stream);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/clearerr.html
stream = FS.getStream(stream);
- if (stream) stream.error = false;
+ if (!stream) {
+ return;
+ }
+ stream.eof = false;
+ stream.error = false;
},
fclose__deps: ['close', 'fsync'],
fclose: function(stream) {
@@ -2322,7 +2326,6 @@ LibraryManager.library = {
if (streamObj.eof || streamObj.error) return -1;
var ret = _fread(_fgetc.ret, 1, 1, stream);
if (ret == 0) {
- streamObj.eof = true;
return -1;
} else if (ret == -1) {
streamObj.error = true;
@@ -5154,6 +5157,37 @@ LibraryManager.library = {
},
// ==========================================================================
+ // termios.h
+ // ==========================================================================
+ tcgetattr: function(fildes, termios_p) {
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/tcgetattr.html
+ var stream = FS.getStream(fildes);
+ if (!stream) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+ if (!stream.tty) {
+ ___setErrNo(ERRNO_CODES.ENOTTY);
+ return -1;
+ }
+ return 0;
+ },
+
+ tcsetattr: function(fildes, optional_actions, termios_p) {
+ // http://pubs.opengroup.org/onlinepubs/7908799/xsh/tcsetattr.html
+ var stream = FS.getStream(fildes);
+ if (!stream) {
+ ___setErrNo(ERRNO_CODES.EBADF);
+ return -1;
+ }
+ if (!stream.tty) {
+ ___setErrNo(ERRNO_CODES.ENOTTY);
+ return -1;
+ }
+ return 0;
+ },
+
+ // ==========================================================================
// time.h
// ==========================================================================
diff --git a/src/library_browser.js b/src/library_browser.js
index 591a3c11..235ccc78 100644
--- a/src/library_browser.js
+++ b/src/library_browser.js
@@ -830,15 +830,21 @@ mergeInto(LibraryManager.library, {
},
emscripten_get_now: function() {
- if (ENVIRONMENT_IS_NODE) {
- var t = process['hrtime']();
- return t[0] * 1e3 + t[1] / 1e6;
- }
- else if (ENVIRONMENT_IS_WEB && window['performance'] && window['performance']['now']) {
- return window['performance']['now']();
- } else {
- return Date.now();
+ if (!_emscripten_get_now.actual) {
+ if (ENVIRONMENT_IS_NODE) {
+ _emscripten_get_now.actual = function() {
+ var t = process['hrtime']();
+ return t[0] * 1e3 + t[1] / 1e6;
+ }
+ } else if (typeof dateNow !== 'undefined') {
+ _emscripten_get_now.actual = dateNow;
+ } else if (ENVIRONMENT_IS_WEB && window['performance'] && window['performance']['now']) {
+ _emscripten_get_now.actual = function() { return window['performance']['now'](); };
+ } else {
+ _emscripten_get_now.actual = Date.now;
+ }
}
+ return _emscripten_get_now.actual();
},
emscripten_create_worker: function(url) {
diff --git a/src/library_fs.js b/src/library_fs.js
index e1397356..1d9748d3 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -510,7 +510,7 @@ mergeInto(LibraryManager.library, {
return FS.create(path, mode);
},
createDataFile: function(parent, name, data, canRead, canWrite, canOwn) {
- var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
+ var path = name ? PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
var mode = FS.getMode(canRead, canWrite);
var node = FS.create(path, mode);
if (data) {
@@ -530,7 +530,7 @@ mergeInto(LibraryManager.library, {
},
createDevice: function(parent, name, input, output) {
var path = PATH.join(typeof parent === 'string' ? parent : FS.getPath(parent), name);
- var mode = input && output ? 0777 : (input ? 0333 : 0555);
+ var mode = FS.getMode(!!input, !!output);
if (!FS.createDevice.major) FS.createDevice.major = 64;
var dev = FS.makedev(FS.createDevice.major++, 0);
// Create a fake device that a set of stream ops to emulate
@@ -770,7 +770,7 @@ mergeInto(LibraryManager.library, {
Browser.init();
// TODO we should allow people to just pass in a complete filename instead
// of parent and name being that we just join them anyways
- var fullname = PATH.resolve(PATH.join(parent, name));
+ var fullname = name ? PATH.resolve(PATH.join(parent, name)) : parent;
function processData(byteArray) {
function finish(byteArray) {
if (!dontCreateFile) {
@@ -802,6 +802,90 @@ mergeInto(LibraryManager.library, {
}
},
+ indexedDB: function() {
+ return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
+ },
+
+ DB_NAME: function() {
+ return 'EM_FS_' + window.location.pathname;
+ },
+ DB_VERSION: 20,
+ DB_STORE_NAME: 'FILE_DATA',
+
+ // asynchronously saves a list of files to an IndexedDB. The DB will be created if not already existing.
+ saveFilesToDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = function() {
+ console.log('creating db');
+ var db = openRequest.result;
+ db.createObjectStore(FS.DB_STORE_NAME);
+ };
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var putRequest = files.put(FS.analyzePath(path).object.contents, path);
+ putRequest.onsuccess = function() { ok++; if (ok + fail == total) finish() };
+ putRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
+ // asychronously loads a file from IndexedDB.
+ loadFilesFromDB: function(paths, onload, onerror) {
+ onload = onload || function(){};
+ onerror = onerror || function(){};
+ var indexedDB = FS.indexedDB();
+ try {
+ var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
+ } catch (e) {
+ return onerror(e);
+ }
+ openRequest.onupgradeneeded = onerror; // no database to load from
+ openRequest.onsuccess = function() {
+ var db = openRequest.result;
+ try {
+ var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
+ } catch(e) {
+ onerror(e);
+ return;
+ }
+ var files = transaction.objectStore(FS.DB_STORE_NAME);
+ var ok = 0, fail = 0, total = paths.length;
+ function finish() {
+ if (fail == 0) onload(); else onerror();
+ }
+ paths.forEach(function(path) {
+ var getRequest = files.get(path);
+ getRequest.onsuccess = function() {
+ if (FS.analyzePath(path).exists) {
+ FS.unlink(path);
+ }
+ FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
+ ok++;
+ if (ok + fail == total) finish();
+ };
+ getRequest.onerror = function() { fail++; if (ok + fail == total) finish() };
+ });
+ transaction.onerror = onerror;
+ };
+ openRequest.onerror = onerror;
+ },
+
//
// general
//
diff --git a/src/library_memfs.js b/src/library_memfs.js
index 63326c42..354f5e95 100644
--- a/src/library_memfs.js
+++ b/src/library_memfs.js
@@ -2,17 +2,13 @@ mergeInto(LibraryManager.library, {
$MEMFS__deps: ['$FS'],
$MEMFS: {
// content modes
- CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it - need to free() when no longer needed
+ CONTENT_OWNING: 1, // contains a subarray into the heap, and we own it, without copying (note: someone else needs to free() it, if that is necessary)
CONTENT_FLEXIBLE: 2, // has been modified or never set to anything, and is a flexible js array that can grow/shrink
CONTENT_FIXED: 3, // contains some fixed-size content written into it, in a typed array
ensureFlexible: function(node) {
if (node.contentMode !== MEMFS.CONTENT_FLEXIBLE) {
var contents = node.contents;
node.contents = Array.prototype.slice.call(contents);
- if (node.contentMode === MEMFS.CONTENT_OWNING) {
- assert(contents.byteOffset);
- Module['_free'](contents.byteOffset);
- }
node.contentMode = MEMFS.CONTENT_FLEXIBLE;
}
},
diff --git a/src/library_path.js b/src/library_path.js
index 2c2c016a..09808acd 100644
--- a/src/library_path.js
+++ b/src/library_path.js
@@ -68,6 +68,9 @@ mergeInto(LibraryManager.library, {
}
return f;
},
+ extname: function(path) {
+ return PATH.splitPath(path)[3];
+ },
join: function() {
var paths = Array.prototype.slice.call(arguments, 0);
return PATH.normalize(paths.filter(function(p, index) {
diff --git a/src/library_sdl.js b/src/library_sdl.js
index 1fb75724..d6cb6d18 100644
--- a/src/library_sdl.js
+++ b/src/library_sdl.js
@@ -46,6 +46,9 @@ var LibrarySDL = {
keyboardState: null,
keyboardMap: {},
+ canRequestFullscreen: false,
+ isRequestingFullscreen: false,
+
textInput: false,
startTime: null,
@@ -467,6 +470,23 @@ var LibrarySDL = {
SDL.DOMButtons[event.button] = 0;
}
+ // We can only request fullscreen as the result of user input.
+ // Due to this limitation, we toggle a boolean on keydown which
+ // SDL_WM_ToggleFullScreen will check and subsequently set another
+ // flag indicating for us to request fullscreen on the following
+ // keyup. This isn't perfect, but it enables SDL_WM_ToggleFullScreen
+ // to work as the result of a keypress (which is an extremely
+ // common use case).
+ if (event.type === 'keydown') {
+ SDL.canRequestFullscreen = true;
+ } else if (event.type === 'keyup') {
+ if (SDL.isRequestingFullscreen) {
+ Module['requestFullScreen'](true, true);
+ SDL.isRequestingFullscreen = false;
+ }
+ SDL.canRequestFullscreen = false;
+ }
+
// SDL expects a unicode character to be passed to its keydown events.
// Unfortunately, the browser APIs only provide a charCode property on
// keypress events, so we must backfill in keydown events with their
@@ -1282,7 +1302,11 @@ var LibrarySDL = {
Module['canvas'].cancelFullScreen();
return 1;
} else {
- return 0;
+ if (!SDL.canRequestFullscreen) {
+ return 0;
+ }
+ SDL.isRequestingFullscreen = true;
+ return 1;
}
},
diff --git a/src/library_tty.js b/src/library_tty.js
index 8f44cd07..53239989 100644
--- a/src/library_tty.js
+++ b/src/library_tty.js
@@ -1,17 +1,35 @@
mergeInto(LibraryManager.library, {
$TTY__deps: ['$FS'],
+ $TTY__postset: '__ATINIT__.unshift({ func: function() { TTY.init() } });' +
+ '__ATEXIT__.push({ func: function() { TTY.shutdown() } });' +
+ 'TTY.utf8 = new Runtime.UTF8Processor();',
$TTY: {
ttys: [],
+ init: function () {
+ if (ENVIRONMENT_IS_NODE) {
+ // currently, FS.init does not distinguish if process.stdin is a file or TTY
+ // device, it always assumes it's a TTY device. because of this, we're forcing
+ // process.stdin to UTF8 encoding to at least make stdin reading compatible
+ // with text files until FS.init can be refactored.
+ process['stdin']['setEncoding']('utf8');
+ }
+ },
+ shutdown: function() {
+ if (ENVIRONMENT_IS_NODE) {
+ // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
+ // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation
+ // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
+ // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
+ // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
+ process['stdin']['pause']();
+ }
+ },
register: function(dev, ops) {
TTY.ttys[dev] = { input: [], output: [], ops: ops };
FS.registerDevice(dev, TTY.stream_ops);
},
stream_ops: {
open: function(stream) {
- // this wouldn't be required if the library wasn't eval'd at first...
- if (!TTY.utf8) {
- TTY.utf8 = new Runtime.UTF8Processor();
- }
var tty = TTY.ttys[stream.node.rdev];
if (!tty) {
throw new FS.ErrnoError(ERRNO_CODES.ENODEV);
@@ -66,17 +84,22 @@ mergeInto(LibraryManager.library, {
return i;
}
},
- // NOTE: This is weird to support stdout and stderr
- // overrides in addition to print and printErr overrides.
default_tty_ops: {
+ // get_char has 3 particular return values:
+ // a.) the next character represented as an integer
+ // b.) undefined to signal that no data is currently available
+ // c.) null to signal an EOF
get_char: function(tty) {
if (!tty.input.length) {
var result = null;
if (ENVIRONMENT_IS_NODE) {
- if (process.stdin.destroyed) {
- return undefined;
+ result = process['stdin']['read']();
+ if (!result) {
+ if (process['stdin']['_readableState'] && process['stdin']['_readableState']['ended']) {
+ return null; // EOF
+ }
+ return undefined; // no data available
}
- result = process.stdin.read();
} else if (typeof window != 'undefined' &&
typeof window.prompt == 'function') {
// Browser.
diff --git a/src/parseTools.js b/src/parseTools.js
index 046dac1b..66354dca 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -430,6 +430,8 @@ function parseParamTokens(params) {
ret.push(parseLLVMFunctionCall(segment));
} else if (segment[1].text === 'blockaddress') {
ret.push(parseBlockAddress(segment));
+ } else if (segment[1].type && segment[1].type == '{') {
+ ret.push(parseLLVMSegment(segment));
} else {
if (segment[2] && segment[2].text == 'to') { // part of bitcast params
segment = segment.slice(0, 2);
diff --git a/src/settings.js b/src/settings.js
index 03b4ed64..02423ba5 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -874,9 +874,9 @@ var C_DEFINES = {
'SOCK_DGRAM': '2',
'SOCK_STREAM': '1',
'STDC_HEADERS': '1',
- 'STDERR_FILENO': '2',
- 'STDIN_FILENO': '0',
- 'STDOUT_FILENO': '1',
+ 'STDERR_FILENO': '3',
+ 'STDIN_FILENO': '1',
+ 'STDOUT_FILENO': '2',
'S_BLKSIZE': '1024',
'S_ENFMT': '0002000',
'S_IEXEC': '0000100',