diff options
author | max99x <max99x@gmail.com> | 2011-06-25 10:41:06 +0300 |
---|---|---|
committer | max99x <max99x@gmail.com> | 2011-06-25 10:41:06 +0300 |
commit | 4217219cd94bb814a485f18f7d041e874f3e86f5 (patch) | |
tree | 645e68c452236e9ab13ac6e14a87ecab6039cf87 /src | |
parent | c7fab4204bee149b2e0c9b2ed02e2bd69e91c572 (diff) |
Added basic support for dynamic module loading.
Diffstat (limited to 'src')
-rw-r--r-- | src/jsifier.js | 19 | ||||
-rw-r--r-- | src/library.js | 117 | ||||
-rw-r--r-- | src/postamble_sharedlib.js | 15 | ||||
-rw-r--r-- | src/settings.js | 3 | ||||
-rw-r--r-- | src/shell_sharedlib.js | 14 |
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; +}); |