Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,13 @@ function analyzer(data) {
var ret = substrate.solve();

// Add additional necessary items
['memset', 'malloc', 'free'].forEach(function(ident) {
if (INCLUDE_FULL_LIBRARY) {
assert(!BUILD_AS_SHARED_LIB, 'Cannot have both INCLUDE_FULL_LIBRARY and BUILD_AS_SHARED_LIB set.')
var libFuncsToInclude = keys(Library);
} else {
var libFuncsToInclude = ['memset', 'malloc', 'free'];
}
libFuncsToInclude.forEach(function(ident) {
ret.functionStubs.push({
intertype: 'functionStub',
ident: '_' + ident
Expand Down
1 change: 1 addition & 0 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ if (SAFE_HEAP >= 2) {
}

EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
EXPORTED_GLOBALS = set(EXPORTED_GLOBALS);

// Settings sanity checks

Expand Down
20 changes: 15 additions & 5 deletions src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
}
}
Expand All @@ -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 (Library.hasOwnProperty(shortident)) {
function addFromLibrary(ident) {
if (ident in addedLibraryItems) return '';
// Don't replace implemented functions with library ones (which can happen when we add dependencies).
Expand Down Expand Up @@ -764,14 +771,17 @@ 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));
var preFile = BUILD_AS_SHARED_LIB ? 'preamble_sharedlib.js' : 'preamble.js';
var pre = processMacros(preprocess(read(preFile).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)); });
Expand Down
122 changes: 121 additions & 1 deletion src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ var Library = {
}
} else {
Module.stdin = function stdin(prompt) {
return window.prompt(prompt);
return window.prompt(prompt) || '';
};
}

Expand Down Expand Up @@ -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
// ==========================================================================
Expand Down
8 changes: 7 additions & 1 deletion src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 + '];';
}
}
};

Expand Down
6 changes: 5 additions & 1 deletion src/parseTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
15 changes: 15 additions & 0 deletions src/postamble_sharedlib.js
Original file line number Diff line number Diff line change
@@ -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}}

2 changes: 1 addition & 1 deletion src/preamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
11 changes: 11 additions & 0 deletions src/preamble_sharedlib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// === Auto-generated preamble library stuff ===

//========================================
// Runtime essentials
//========================================

var __globalConstructor__ = function globalConstructor() {
}

// === Body ===

12 changes: 12 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,20 @@ 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.

INCLUDE_FULL_LIBRARY = 0; // Whether to include the whole library rather than just the
// functions used by the generated code. This is needed when
// dynamically loading modules that make use of runtime
// library functions that are not used in the main module.

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:
Expand Down
14 changes: 14 additions & 0 deletions src/shell_sharedlib.js
Original file line number Diff line number Diff line change
@@ -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;
});
Loading