refactor dlfcn support into DLFCN

This commit is contained in:
Alon Zakai 2013-09-03 14:56:00 -07:00
Родитель dcf8f0c29c
Коммит f2783ad485
4 изменённых файлов: 78 добавлений и 78 удалений

Просмотреть файл

@ -638,7 +638,7 @@ Runtime.stackRestore = function(top) { asm['stackRestore'](top) };
if settings.get('DLOPEN_SUPPORT'):
funcs_js.append('''
asm.maxFunctionIndex = %(max_mask)d;
Runtime.registerFunctions(asm, %(max_mask)d+1, %(sigs)s, Module);
DLFCN.registerFunctions(asm, %(max_mask)d+1, %(sigs)s, Module);
Module.SYMBOL_TABLE = SYMBOL_TABLE;
''' % { 'max_mask': max_mask, 'sigs': str(map(str, last_forwarded_json['Functions']['tables'].keys())) })

Просмотреть файл

@ -5018,24 +5018,68 @@ LibraryManager.library = {
// being compiled. Not sure how to tell LLVM to not do so.
// ==========================================================================
// Data for dlfcn.h.
$DLFCN_DATA: {
$DLFCN: {
#if DLOPEN_SUPPORT
// extra asm.js dlopen support
functionTable: [], // will contain objects mapping sigs to js functions that call into the right asm module with the right index
registerFunctions: function(asm, num, sigs, jsModule) {
// use asm module dynCall_* from functionTable
if (num % 2 == 1) num++; // keep pointers even
var table = DLFCN.functionTable;
var from = table.length;
assert(from % 2 == 0);
for (var i = 0; i < num; i++) {
table[from + i] = {};
sigs.forEach(function(sig) { // TODO: new Function etc.
var full = 'dynCall_' + sig;
table[from + i][sig] = function() {
arguments[0] -= from;
return asm[full].apply(null, arguments);
}
});
}
if (jsModule.cleanups) {
var newLength = table.length;
jsModule.cleanups.push(function() {
if (table.length === newLength) {
table.length = from; // nothing added since, just shrink
} else {
// something was added above us, clear and leak the span
for (var i = 0; i < num; i++) {
table[from + i] = null;
}
}
while (table.length > 0 && table[table.length-1] === null) table.pop();
});
}
// patch js module dynCall_* to use functionTable
sigs.forEach(function(sig) {
jsModule['dynCall_' + sig] = function() {
return table[arguments[0]][sig].apply(null, arguments);
};
});
},
#endif
error: null,
errorMsg: null,
loadedLibs: {}, // handle -> [refcount, name, lib_object]
loadedLibNames: {}, // name -> handle
},
// void* dlopen(const char* filename, int flag);
dlopen__deps: ['$DLFCN_DATA', '$FS', '$ENV'],
dlopen__deps: ['$DLFCN', '$FS', '$ENV'],
dlopen: function(filename, flag) {
// void *dlopen(const char *file, int mode);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename);
if (DLFCN_DATA.loadedLibNames[filename]) {
if (DLFCN.loadedLibNames[filename]) {
// Already loaded; increment ref count and return.
var handle = DLFCN_DATA.loadedLibNames[filename];
DLFCN_DATA.loadedLibs[handle].refcount++;
var handle = DLFCN.loadedLibNames[filename];
DLFCN.loadedLibs[handle].refcount++;
return handle;
}
@ -5046,7 +5090,7 @@ LibraryManager.library = {
} else {
var target = FS.findObject(filename);
if (!target || target.isFolder || target.isDevice) {
DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename;
DLFCN.errorMsg = 'Could not find dynamic lib: ' + filename;
return 0;
} else {
FS.forceLoadFile(target);
@ -5056,7 +5100,7 @@ LibraryManager.library = {
try {
var lib_module = eval(lib_data)(
#if ASM_JS
Runtime.functionTable.length,
DLFCN.functionTable.length,
#else
{{{ Functions.getTable('x') }}}.length,
#endif
@ -5066,14 +5110,14 @@ LibraryManager.library = {
#if ASSERTIONS
Module.printErr('Error in loading dynamic library: ' + e);
#endif
DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
DLFCN.errorMsg = 'Could not evaluate dynamic lib: ' + filename;
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++;
for (var key in DLFCN.loadedLibs) {
if (DLFCN.loadedLibs.hasOwnProperty(key)) handle++;
}
// We don't care about RTLD_NOW and RTLD_LAZY.
@ -5087,55 +5131,55 @@ LibraryManager.library = {
var cached_functions = {};
}
DLFCN_DATA.loadedLibs[handle] = {
DLFCN.loadedLibs[handle] = {
refcount: 1,
name: filename,
module: lib_module,
cached_functions: cached_functions
};
DLFCN_DATA.loadedLibNames[filename] = handle;
DLFCN.loadedLibNames[filename] = handle;
return handle;
},
// int dlclose(void* handle);
dlclose__deps: ['$DLFCN_DATA'],
dlclose__deps: ['$DLFCN'],
dlclose: function(handle) {
// int dlclose(void *handle);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlclose.html
if (!DLFCN_DATA.loadedLibs[handle]) {
DLFCN_DATA.errorMsg = 'Tried to dlclose() unopened handle: ' + handle;
if (!DLFCN.loadedLibs[handle]) {
DLFCN.errorMsg = 'Tried to dlclose() unopened handle: ' + handle;
return 1;
} else {
var lib_record = DLFCN_DATA.loadedLibs[handle];
var lib_record = DLFCN.loadedLibs[handle];
if (--lib_record.refcount == 0) {
if (lib_record.module.cleanups) {
lib_record.module.cleanups.forEach(function(cleanup) { cleanup() });
}
delete DLFCN_DATA.loadedLibNames[lib_record.name];
delete DLFCN_DATA.loadedLibs[handle];
delete DLFCN.loadedLibNames[lib_record.name];
delete DLFCN.loadedLibs[handle];
}
return 0;
}
},
// void* dlsym(void* handle, const char* symbol);
dlsym__deps: ['$DLFCN_DATA'],
dlsym__deps: ['$DLFCN'],
dlsym: function(handle, symbol) {
// void *dlsym(void *restrict handle, const char *restrict name);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
symbol = '_' + Pointer_stringify(symbol);
if (!DLFCN_DATA.loadedLibs[handle]) {
DLFCN_DATA.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle;
if (!DLFCN.loadedLibs[handle]) {
DLFCN.errorMsg = 'Tried to dlsym() from an unopened handle: ' + handle;
return 0;
} else {
var lib = DLFCN_DATA.loadedLibs[handle];
var lib = DLFCN.loadedLibs[handle];
// self-dlopen means that lib.module is not a superset of
// cached_functions, so check the latter first
if (lib.cached_functions.hasOwnProperty(symbol)) {
return lib.cached_functions[symbol];
} else {
if (!lib.module.hasOwnProperty(symbol)) {
DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
DLFCN.errorMsg = ('Tried to lookup unknown symbol "' + symbol +
'" in dynamic lib: ' + lib.name);
return 0;
} else {
@ -5155,18 +5199,18 @@ LibraryManager.library = {
}
},
// char* dlerror(void);
dlerror__deps: ['$DLFCN_DATA'],
dlerror__deps: ['$DLFCN'],
dlerror: function() {
// char *dlerror(void);
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlerror.html
if (DLFCN_DATA.errorMsg === null) {
if (DLFCN.errorMsg === null) {
return 0;
} else {
if (DLFCN_DATA.error) _free(DLFCN_DATA.error);
var msgArr = intArrayFromString(DLFCN_DATA.errorMsg);
DLFCN_DATA.error = allocate(msgArr, 'i8', ALLOC_NORMAL);
DLFCN_DATA.errorMsg = null;
return DLFCN_DATA.error;
if (DLFCN.error) _free(DLFCN.error);
var msgArr = intArrayFromString(DLFCN.errorMsg);
DLFCN.error = allocate(msgArr, 'i8', ALLOC_NORMAL);
DLFCN.errorMsg = null;
return DLFCN.error;
}
},

Просмотреть файл

@ -384,50 +384,6 @@ var Runtime = {
return Runtime.funcWrappers[func];
},
#if DLOPEN_SUPPORT
functionTable: [], // will contain objects mapping sigs to js functions that call into the right asm module with the right index
registerFunctions: function(asm, num, sigs, jsModule) {
// use asm module dynCall_* from functionTable
if (num % 2 == 1) num++; // keep pointers even
var table = Runtime.functionTable;
var from = table.length;
assert(from % 2 == 0);
for (var i = 0; i < num; i++) {
table[from + i] = {};
sigs.forEach(function(sig) { // TODO: new Function etc.
var full = 'dynCall_' + sig;
table[from + i][sig] = function() {
arguments[0] -= from;
return asm[full].apply(null, arguments);
}
});
}
if (jsModule.cleanups) {
var newLength = table.length;
jsModule.cleanups.push(function() {
if (table.length === newLength) {
table.length = from; // nothing added since, just shrink
} else {
// something was added above us, clear and leak the span
for (var i = 0; i < num; i++) {
table[from + i] = null;
}
}
while (table.length > 0 && table[table.length-1] === null) table.pop();
});
}
// patch js module dynCall_* to use functionTable
sigs.forEach(function(sig) {
jsModule['dynCall_' + sig] = function() {
return table[arguments[0]][sig].apply(null, arguments);
};
});
},
#endif
// Returns a processor of UTF.
// processCChar() receives characters from a C-like UTF representation and returns JS string fragments.
// See RFC3629 for details, the bytes are assumed to be valid UTF-8

Просмотреть файл

@ -354,8 +354,8 @@ var LINKABLE = 0; // If set to 1, this file can be linked with others, either as
// LINKABLE of 0 is very useful in that we can reduce the size of the
// generated code very significantly, by removing everything not actually used.
var DLOPEN_SUPPORT = 0; // Whether to support dlopen(NULL, ...) which enables dynamic access to the
// module's functions and globals. Note that you must use EMSCRIPTEN_KEEPALIVE
var DLOPEN_SUPPORT = 0; // Full support for dlopen. This is necessary for asm.js and for all code
// modes for dlopen(NULL, ...). Note that you must use EMSCRIPTEN_KEEPALIVE
// to ensure that functions and globals can be accessed through dlsym,
// otherwise LLVM may optimize them out.