diff options
-rw-r--r-- | src/compiler.js | 1 | ||||
-rw-r--r-- | src/jsifier.js | 23 | ||||
-rw-r--r-- | src/library.js | 122 | ||||
-rw-r--r-- | src/modules.js | 8 | ||||
-rw-r--r-- | src/parseTools.js | 6 | ||||
-rw-r--r-- | src/postamble_sharedlib.js | 15 | ||||
-rw-r--r-- | src/preamble.js | 6 | ||||
-rw-r--r-- | src/settings.js | 7 | ||||
-rw-r--r-- | src/shell_sharedlib.js | 14 |
9 files changed, 190 insertions, 12 deletions
diff --git a/src/compiler.js b/src/compiler.js index e5e8a755..4fe68e88 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -42,6 +42,7 @@ if (SAFE_HEAP >= 2) { } EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS); +EXPORTED_GLOBALS = set(EXPORTED_GLOBALS); // Settings sanity checks diff --git a/src/jsifier.js b/src/jsifier.js index d3a197b6..9621bb8e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -178,9 +178,13 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { } constant = makePointer(constant, null, 'ALLOC_STATIC', item.type); + var js = item.ident + '=' + constant + ';'; + if (item.ident in EXPORTED_GLOBALS) { + js += '\nModule["' + item.ident + '"] = ' + item.ident + ';'; + } return ret.concat({ intertype: 'GlobalVariable', - JS: item.ident + '=' + constant + ';', + JS: js, }); } } @@ -196,7 +200,10 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { processItem: function(item) { var ret = [item]; var shortident = item.ident.substr(1); - if (shortident in Library) { + if (BUILD_AS_SHARED_LIB) { + // Shared libraries reuse the runtime of their parents. + item.JS = ''; + } else if (shortident in Library) { function addFromLibrary(ident) { if (ident in addedLibraryItems) return ''; // Don't replace implemented functions with library ones (which can happen when we add dependencies). @@ -764,14 +771,18 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { // postamble // global_vars - var shellParts = read('shell.js').split('{{BODY}}'); + var shellFile = BUILD_AS_SHARED_LIB ? 'shell_sharedlib.js' : 'shell.js'; + var shellParts = read(shellFile).split('{{BODY}}'); print(shellParts[0]); - var pre = processMacros(preprocess(read('preamble.js').replace('{{RUNTIME}}', getRuntime()), CONSTANTS)); - print(pre); + if (!BUILD_AS_SHARED_LIB) { + var pre = processMacros(preprocess(read('preamble.js').replace('{{RUNTIME}}', getRuntime()), CONSTANTS)); + print(pre); + } generated.forEach(function(item) { print(indentify(item.JS || '', 2)); }); print(Functions.generateIndexing()); - var postParts = processMacros(preprocess(read('postamble.js'), CONSTANTS)).split('{{GLOBAL_VARS}}'); + var postFile = BUILD_AS_SHARED_LIB ? 'postamble_sharedlib.js' : 'postamble.js'; + var postParts = processMacros(preprocess(read(postFile), CONSTANTS)).split('{{GLOBAL_VARS}}'); print(postParts[0]); itemsDict.GlobalVariable.forEach(function(item) { print(indentify(item.JS, 4)); }); itemsDict.GlobalVariablePostSet.forEach(function(item) { print(indentify(item.JS, 4)); }); diff --git a/src/library.js b/src/library.js index 42e2cc5c..083bf29c 100644 --- a/src/library.js +++ b/src/library.js @@ -277,7 +277,7 @@ var Library = { } } else { Module.stdin = function stdin(prompt) { - return window.prompt(prompt); + return window.prompt(prompt) || ''; }; } @@ -1194,6 +1194,126 @@ var Library = { return Math.pow(2, x); }, + + // ========================================================================== + // dlfcn.h + // ========================================================================== + + // Data for dlfcn.h. + $DLFCN_DATA: { + error: null, + isError: false, + loadedLibs: {}, // handle -> [refcount, name, lib_object] + loadedLibNames: {}, // name -> handle + }, + // void* dlopen(const char* filename, int flag); + dlopen__deps: ['$DLFCN_DATA'], + dlopen: function(filename, flag) { + // TODO: Add support for LD_LIBRARY_PATH. + filename = Pointer_stringify(filename); + filename += '.js'; + + if (DLFCN_DATA.loadedLibNames[filename]) { + // Already loaded; increment ref count and return. + var handle = DLFCN_DATA.loadedLibNames[filename]; + DLFCN_DATA.loadedLibs[handle][0]++; + return handle; + } + + try { + var lib_data = read(filename); + } catch (e) { + DLFCN_DATA.isError = true; + return 0; + } + + try { + var lib_module = eval(lib_data)(FUNCTION_TABLE.length); + } catch (e) { + DLFCN_DATA.isError = true; + return 0; + } + + // Not all browsers support Object.keys(). + var handle = 1; + for (var key in DLFCN_DATA.loadedLibs) { + if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) handle++; + } + + DLFCN_DATA.loadedLibs[handle] = [1, filename, lib_module]; + DLFCN_DATA.loadedLibNames[filename] = handle; + + // We don't care about RTLD_NOW and RTLD_LAZY. + if (flag & 256) { // RTLD_GLOBAL + for (var ident in lib_module) { + if (lib_module.hasOwnProperty(ident)) { + // TODO: Check if we need to unmangle here. + Module[ident] = lib_module[ident]; + } + } + } + + return handle; + }, + // int dlclose(void* handle); + dlclose__deps: ['$DLFCN_DATA'], + dlclose: function(handle) { + if (!DLFCN_DATA.loadedLibs[handle]) { + DLFCN_DATA.isError = true; + return 1; + } else { + var lib_record = DLFCN_DATA.loadedLibs[handle]; + if (lib_record[0]-- == 0) { + delete DLFCN_DATA.loadedLibNames[lib_record[1]]; + delete DLFCN_DATA.loadedLibs[handle]; + } + return 0; + } + }, + // void* dlsym(void* handle, const char* symbol); + dlsym__deps: ['$DLFCN_DATA'], + dlsym: function(handle, symbol) { + symbol = Pointer_stringify(symbol); + // TODO: Properly mangle. + symbol = '_' + symbol; + + if (!DLFCN_DATA.loadedLibs[handle]) { + DLFCN_DATA.isError = true; + return 0; + } else { + var lib_module = DLFCN_DATA.loadedLibs[handle][2]; + if (!lib_module[symbol]) { + DLFCN_DATA.isError = true; + return 0; + } else { + var result = lib_module[symbol]; + if (typeof result == 'function') { + // TODO: Cache functions rather than appending on every lookup. + FUNCTION_TABLE.push(result); + FUNCTION_TABLE.push(0); + result = FUNCTION_TABLE.length - 2; + } + return result; + } + } + }, + // char* dlerror(void); + dlerror__deps: ['$DLFCN_DATA'], + dlerror: function() { + if (DLFCN_DATA.isError) { + return 0; + } else { + // TODO: Return non-generic error messages. + if (DLFCN_DATA.error === null) { + var msg = 'An error occurred while loading dynamic library.'; + var arr = Module.intArrayFromString(msg) + DLFCN_DATA.error = Pointer_make(arr, 0, 2, 'i8'); + } + DLFCN_DATA.isError = false; + return DLFCN_DATA.error; + } + }, + // ========================================================================== // unistd.h // ========================================================================== diff --git a/src/modules.js b/src/modules.js index fd18fc72..91758609 100644 --- a/src/modules.js +++ b/src/modules.js @@ -140,7 +140,13 @@ var Functions = { // Generate code for function indexing generateIndexing: function() { - return 'var FUNCTION_TABLE = [' + this.indexedFunctions.toString().replace('"', '') + '];'; + var indices = this.indexedFunctions.toString().replace('"', ''); + if (BUILD_AS_SHARED_LIB) { + // Shared libraries reuse the parent's function table. + return 'FUNCTION_TABLE = FUNCTION_TABLE.concat([' + indices + ']);'; + } else { + return 'var FUNCTION_TABLE = [' + indices + '];'; + } } }; diff --git a/src/parseTools.js b/src/parseTools.js index e520f919..39537ab2 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -694,7 +694,11 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned) { function indexizeFunctions(value) { if (value in Functions.currFunctions) { - return Functions.getIndex(value); + if (BUILD_AS_SHARED_LIB) { + return '(FUNCTION_TABLE_OFFSET + ' + Functions.getIndex(value) + ')'; + } else { + return Functions.getIndex(value); + } } if (value && value[0] && value[0] == '_') { var rootIdent = LibraryManager.getRootIdent(value.slice(1)); diff --git a/src/postamble_sharedlib.js b/src/postamble_sharedlib.js new file mode 100644 index 00000000..1fd78f23 --- /dev/null +++ b/src/postamble_sharedlib.js @@ -0,0 +1,15 @@ + +// === Auto-generated postamble setup entry stuff === + +function run(args) { + {{GLOBAL_VARS}} + __globalConstructor__(); +} +Module['run'] = run; + +// {{PRE_RUN_ADDITIONS}} + +run(); + +// {{POST_RUN_ADDITIONS}} + diff --git a/src/preamble.js b/src/preamble.js index 0575178d..8ee543a7 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -589,8 +589,8 @@ function intArrayToString(array) { {{{ reSign }}} // Use console read if available, otherwise we are in a browser, use an XHR -if (!this['read']) { - this['read'] = function(url) { +if (this.read === undefined) { + var read = function(url) { // TODO: use mozResponseArrayBuffer/responseStream/etc. if available var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); @@ -598,7 +598,7 @@ if (!this['read']) { xhr.send(null); if (xhr.status != 200 && xhr.status != 0) throw 'failed to open: ' + url; return xhr.responseText; - } + }; } function readBinary(filename) { diff --git a/src/settings.js b/src/settings.js index f2dd9065..614a29ac 100644 --- a/src/settings.js +++ b/src/settings.js @@ -101,8 +101,15 @@ AUTO_OPTIMIZE = 0; // When run with the CHECK_* options, will not fail on errors EXPORTED_FUNCTIONS = ['_main']; // Functions that are explicitly exported, so they are guaranteed to // be accessible outside of the generated code. +EXPORTED_GLOBALS = []; // Global non-function variables that are explicitly + // exported, so they are guaranteed to be + // accessible outside of the generated code. + SHOW_LABELS = 0; // Show labels in the generated code +BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library, which + // must be loaded dynamically using dlopen(). + // Compiler debugging options DEBUG_TAGS_SHOWING = []; // Some useful items: diff --git a/src/shell_sharedlib.js b/src/shell_sharedlib.js new file mode 100644 index 00000000..cbdac74b --- /dev/null +++ b/src/shell_sharedlib.js @@ -0,0 +1,14 @@ +"use strict"; + +// Capture the output of this into a variable, if you want +(function(FUNCTION_TABLE_OFFSET) { + var Module = {}; + var args = []; + Module.arguments = []; + + {{BODY}} + + // {{MODULE_ADDITIONS}} + + return Module; +}); |