aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormax99x <max99x@gmail.com>2011-06-25 10:41:06 +0300
committermax99x <max99x@gmail.com>2011-06-25 10:41:06 +0300
commit4217219cd94bb814a485f18f7d041e874f3e86f5 (patch)
tree645e68c452236e9ab13ac6e14a87ecab6039cf87 /src
parentc7fab4204bee149b2e0c9b2ed02e2bd69e91c572 (diff)
Added basic support for dynamic module loading.
Diffstat (limited to 'src')
-rw-r--r--src/jsifier.js19
-rw-r--r--src/library.js117
-rw-r--r--src/postamble_sharedlib.js15
-rw-r--r--src/settings.js3
-rw-r--r--src/shell_sharedlib.js14
5 files changed, 163 insertions, 5 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index 71797daa..27b27252 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -261,7 +261,12 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) {
} else {
ident = '_' + ident;
}
- return (deps ? '\n' + deps.map(addFromLibrary).join('\n') : '') + 'var ' + ident + '=' + snippet + ';';
+ var depsString = deps ? '\n' + deps.map(addFromLibrary).join('\n') : '';
+ var defString = 'var ' + ident + '=' + snippet + ';';
+ if (BUILD_AS_SHARED_LIB) {
+ defString = 'if (typeof ' + ident + ' == "undefined") {\n ' + defString + '\n}';
+ }
+ return depsString + defString;
}
item.JS = addFromLibrary(shortident);
} else {
@@ -764,14 +769,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 c73b94ad..d2b05764 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1194,6 +1194,123 @@ var Library = {
return Math.pow(2, x);
},
+
+ // ==========================================================================
+ // dlfcn.h
+ // ==========================================================================
+
+ // Data for dlfcn.h.
+ $DLFCN_DATA: {
+ error: null,
+ is_error: false,
+ loaded_libs: {}, // handle -> [refcount, name, lib_object]
+ loaded_lib_names: {}, // name -> handle
+ },
+ // void* dlopen(const char* filename, int flag);
+ dlopen__deps: ['$DLFCN_DATA'],
+ dlopen: function(filename, flag) {
+ filename = Pointer_stringify(filename);
+ filename += '.js';
+
+ if (DLFCN_DATA.loaded_lib_names[filename]) {
+ // Already loaded; increment ref count and return.
+ var handle = DLFCN_DATA.loaded_lib_names[filename];
+ DLFCN_DATA.loaded_libs[handle][0]++;
+ return handle;
+ }
+
+ try {
+ var lib_data = read(filename);
+ } catch (e) {
+ DLFCN_DATA.is_error = true;
+ return 0;
+ }
+
+ try {
+ var lib_module = eval(lib_data)();
+ } catch (e) {
+ DLFCN_DATA.is_error = true;
+ return 0;
+ }
+
+ // Not all browsers support Object.keys().
+ var handle = 1;
+ for (var key in DLFCN_DATA.loaded_libs) {
+ if (DLFCN_DATA.loaded_libs.hasOwnProperty(key)) handle++;
+ }
+
+ DLFCN_DATA.loaded_libs[handle] = [1, filename, lib_module];
+ DLFCN_DATA.loaded_lib_names[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.loaded_libs[handle]) {
+ DLFCN_DATA.is_error = true;
+ return 1;
+ } else {
+ var lib_record = DLFCN_DATA.loaded_libs[handle];
+ if (lib_record[0]-- == 0) {
+ delete DLFCN_DATA.loaded_lib_names[lib_record[1]];
+ delete DLFCN_DATA.loaded_libs[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.loaded_libs[handle]) {
+ DLFCN_DATA.is_error = true;
+ return 0;
+ } else {
+ var lib_module = DLFCN_DATA.loaded_libs[handle][2];
+ if (!lib_module[symbol]) {
+ DLFCN_DATA.is_error = true;
+ return 0;
+ } else {
+ var result = lib_module[symbol];
+ if (typeof result == 'function') {
+ FUNCTION_TABLE.push(result);
+ result = FUNCTION_TABLE.length - 1;
+ }
+ return result;
+ }
+ }
+ },
+ // char* dlerror(void);
+ dlerror__deps: ['$DLFCN_DATA'],
+ dlerror: function() {
+ if (DLFCN_DATA.is_error) {
+ 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.is_error = false;
+ return DLFCN_DATA.error;
+ }
+ },
+
// ==========================================================================
// unistd.h
// ==========================================================================
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/settings.js b/src/settings.js
index f3ed4d06..b756822c 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -107,6 +107,9 @@ EXPORTED_GLOBALS = []; // Global non-function variables that are explicitly
SHOW_LABELS = 0; // Show labels in the generated code
+BUILD_AS_SHARED_LIB = 1; // 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..d7af23fc
--- /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() {
+ var Module = {};
+ var args = [];
+ Module.arguments = [];
+
+ {{BODY}}
+
+ // {{MODULE_ADDITIONS}}
+
+ return Module;
+});