diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-08-30 11:21:48 -0700 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-08-30 11:21:48 -0700 |
commit | b5b49215d4a40566380a769f47a9c1cce74a28b0 (patch) | |
tree | 68308b6059798a81f24f6a8a1ac28a0091c5d066 /src | |
parent | 1cc28b8e9e94267041bc71afebfbbe3059db4a3f (diff) | |
parent | b895cdc7df2085d324003c9df582a3dcc1927697 (diff) |
Merge branch 'incoming'
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 8 | ||||
-rw-r--r-- | src/jsifier.js | 18 | ||||
-rw-r--r-- | src/library.js | 38 | ||||
-rw-r--r-- | src/library_browser.js | 22 | ||||
-rw-r--r-- | src/library_fs.js | 90 | ||||
-rw-r--r-- | src/library_memfs.js | 6 | ||||
-rw-r--r-- | src/library_path.js | 3 | ||||
-rw-r--r-- | src/library_sdl.js | 26 | ||||
-rw-r--r-- | src/library_tty.js | 41 | ||||
-rw-r--r-- | src/parseTools.js | 2 | ||||
-rw-r--r-- | src/settings.js | 6 |
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', |