aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler.js1
-rw-r--r--src/jsifier.js23
-rw-r--r--src/library.js122
-rw-r--r--src/modules.js8
-rw-r--r--src/parseTools.js6
-rw-r--r--src/postamble_sharedlib.js15
-rw-r--r--src/preamble.js6
-rw-r--r--src/settings.js7
-rw-r--r--src/shell_sharedlib.js14
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;
+});