aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/intertyper.js11
-rw-r--r--src/jsifier.js40
-rw-r--r--src/library.js239
-rw-r--r--src/library_fs.js1389
-rw-r--r--src/library_gl.js15
-rw-r--r--src/library_openal.js17
-rw-r--r--src/library_sdl.js53
-rw-r--r--src/library_tty.js32
-rw-r--r--src/modules.js8
-rw-r--r--src/parseTools.js9
-rw-r--r--src/postamble.js4
-rw-r--r--src/preamble.js4
-rw-r--r--src/proxyClient.js71
-rw-r--r--src/proxyWorker.js128
-rw-r--r--src/settings.js10
-rw-r--r--src/shell_sharedlib.js19
16 files changed, 1255 insertions, 794 deletions
diff --git a/src/intertyper.js b/src/intertyper.js
index 31e97bd0..f9633549 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -707,16 +707,25 @@ function intertyper(data, sidePass, baseLineNums) {
var tokensLeft = item.tokens.slice(2);
item.ident = eatLLVMIdent(tokensLeft);
if (item.ident == 'asm') {
+ if (ASM_JS) {
+ Types.hasInlineJS = true;
+ warnOnce('inline JavaScript (asm, EM_ASM) will cause the code to no longer fall in the asm.js subset of JavaScript, which can reduce performance');
+ }
+ assert(TARGET_LE32, 'inline js is only supported in le32');
// Inline assembly is just JavaScript that we paste into the code
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
var i = 0;
+ var params = [], args = [];
splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
var ident = toNiceIdent(element[1].text);
var type = element[0].text;
- item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident);
+ params.push('$' + (i++));
+ args.push(ident);
});
+ if (item.assignTo) item.ident = 'return ' + item.ident;
+ item.ident = '(function(' + params + ') { ' + item.ident + ' })(' + args + ');';
return { forward: null, ret: [item], item: item };
}
if (item.ident.substr(-2) == '()') {
diff --git a/src/jsifier.js b/src/jsifier.js
index da2ba749..a3b26aa9 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -324,11 +324,13 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);
// This is a flattened object. We need to find its idents, so they can be assigned to later
+ var structTypes = null;
constant.forEach(function(value, i) {
if (needsPostSet(value)) { // ident, or expression containing an ident
+ if (!structTypes) structTypes = generateStructTypes(item.type);
ret.push({
intertype: 'GlobalVariablePostSet',
- JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
+ JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
});
constant[i] = '0';
}
@@ -338,6 +340,7 @@ function JSify(data, functionsOnly, givenFunctions) {
// External variables in shared libraries should not be declared as
// they would shadow similarly-named globals in the parent, so do nothing here.
if (BUILD_AS_SHARED_LIB) return ret;
+ if (SIDE_MODULE) return [];
// Library items need us to emit something, but everything else requires nothing.
if (!LibraryManager.library[item.ident.slice(1)]) return ret;
}
@@ -1142,8 +1145,8 @@ function JSify(data, functionsOnly, givenFunctions) {
});
var range = maxx - minn;
var useIfs = (item.switchLabels.length+1) < 6 || range > 10*1024 || (range/item.switchLabels.length) > 1024; // heuristics
- if (VERBOSE && useIfs && item.switchLabels.length > 2) {
- warn('not optimizing llvm switch into js switch because ' + [range, range/item.switchLabels.length]);
+ if (VERBOSE && useIfs && item.switchLabels.length >= 6) {
+ warn('not optimizing llvm switch into js switch because range of values is ' + range + ', density is ' + range/item.switchLabels.length);
}
var phiSets = calcPhiSets(item);
@@ -1405,7 +1408,10 @@ function JSify(data, functionsOnly, givenFunctions) {
// We cannot compile assembly. See comment in intertyper.js:'Call'
assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!');
+ var extCall = false;
+
if (ASM_JS && funcData.setjmpTable) forceByPointer = true; // in asm.js mode, we must do an invoke for each call
+ if (ASM_JS && DLOPEN_SUPPORT && !invoke && !funcData.setjmpTable) extCall = true; // go out, to be able to access other modules TODO: optimize
ident = Variables.resolveAliasToIdent(ident);
var shortident = ident.slice(1);
@@ -1466,7 +1472,7 @@ function JSify(data, functionsOnly, givenFunctions) {
args = args.map(function(arg, i) { return indexizeFunctions(arg, argsTypes[i]) });
if (ASM_JS) {
- if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || funcData.setjmpTable) {
+ if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || extCall || funcData.setjmpTable) {
args = args.map(function(arg, i) { return asmCoercion(arg, argsTypes[i]) });
} else {
args = args.map(function(arg, i) { return asmEnsureFloat(arg, argsTypes[i]) });
@@ -1556,17 +1562,17 @@ function JSify(data, functionsOnly, givenFunctions) {
var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs);
if (ASM_JS) {
assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out)
- var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke;
+ Functions.neededTables[sig] = 1;
+ var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke && !extCall;
if (functionTableCall) {
// normal asm function pointer call
callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py
- Functions.neededTables[sig] = 1;
} else {
- // This is a call through an invoke_*, either a forced one, or a setjmp-required one
+ // This is a call through an invoke_* or extCall, either a forced one, or a setjmp-required one
// note: no need to update argsTypes at this point
if (byPointerForced) Functions.unimplementedFunctions[callIdent] = sig;
args.unshift(byPointerForced ? Functions.getIndex(callIdent, sig) : asmCoercion(callIdent, 'i32'));
- callIdent = 'invoke_' + sig;
+ callIdent = (extCall ? 'extCall' : 'invoke') + '_' + sig;
}
} else if (SAFE_DYNCALLS) {
assert(!ASM_JS, 'cannot emit safe dyncalls in asm');
@@ -1660,8 +1666,13 @@ function JSify(data, functionsOnly, givenFunctions) {
Variables.generatedGlobalBase = true;
// Globals are done, here is the rest of static memory
assert((TARGET_LE32 && Runtime.GLOBAL_BASE == 8) || (TARGET_X86 && Runtime.GLOBAL_BASE == 4)); // this is assumed in e.g. relocations for linkable modules
- print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n');
- print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
+ if (!SIDE_MODULE) {
+ print('STATIC_BASE = ' + Runtime.GLOBAL_BASE + ';\n');
+ print('STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n');
+ } else {
+ print('H_BASE = parentModule["_malloc"](' + Runtime.alignMemory(Variables.nextIndexedOffset) + ' + Runtime.GLOBAL_BASE);\n');
+ print('// STATICTOP = STATIC_BASE + ' + Runtime.alignMemory(Variables.nextIndexedOffset) + ';\n'); // comment as metadata only
+ }
}
var generated = itemsDict.function.concat(itemsDict.type).concat(itemsDict.GlobalVariableStub).concat(itemsDict.GlobalVariable);
print(generated.map(function(item) { return item.JS; }).join('\n'));
@@ -1688,7 +1699,7 @@ function JSify(data, functionsOnly, givenFunctions) {
return true;
});
// write out the singleton big memory initialization value
- print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE', true));
+ print('/* memory initializer */ ' + makePointer(memoryInitialization, null, 'ALLOC_NONE', 'i8', 'Runtime.GLOBAL_BASE' + (SIDE_MODULE ? '+H_BASE' : ''), true));
} else {
print('/* no memory initializer */'); // test purposes
}
@@ -1700,7 +1711,7 @@ function JSify(data, functionsOnly, givenFunctions) {
print('}\n');
if (USE_TYPED_ARRAYS == 2) {
- if (!BUILD_AS_SHARED_LIB) {
+ if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
print('var tempDoublePtr = Runtime.alignMemory(allocate(12, "i8", ALLOC_STATIC), 8);\n');
print('assert(tempDoublePtr % 8 == 0);\n');
print('function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n');
@@ -1754,7 +1765,7 @@ function JSify(data, functionsOnly, givenFunctions) {
legalizedI64s = legalizedI64sDefault;
- if (!BUILD_AS_SHARED_LIB) {
+ if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) {
print('STACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n');
print('staticSealed = true; // seal the static portion of memory\n');
print('STACK_MAX = STACK_BASE + ' + TOTAL_STACK + ';\n');
@@ -1832,6 +1843,9 @@ function JSify(data, functionsOnly, givenFunctions) {
print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace("'?%s'", "'/'").replace('%s,', 'null,').replace('%d', '0'));
print('}');
}
+ if (PROXY_TO_WORKER) {
+ print(read('proxyWorker.js'));
+ }
if (RUNTIME_TYPE_INFO) {
Types.cleanForRuntime();
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
diff --git a/src/library.js b/src/library.js
index 9d0c65d5..f3c3c1ec 100644
--- a/src/library.js
+++ b/src/library.js
@@ -323,10 +323,16 @@ LibraryManager.library = {
path = Pointer_stringify(path);
// we don't want this in the JS API as the JS API
// uses mknod to create all nodes.
- var err = FS.mayMknod(mode);
- if (err) {
- ___setErrNo(err);
- return -1;
+ switch (mode & {{{ cDefine('S_IFMT') }}}) {
+ case {{{ cDefine('S_IFREG') }}}:
+ case {{{ cDefine('S_IFCHR') }}}:
+ case {{{ cDefine('S_IFBLK') }}}:
+ case {{{ cDefine('S_IFIFO') }}}:
+ case {{{ cDefine('S_IFSOCK') }}}:
+ break;
+ default:
+ ___setErrNo(ERRNO_CODES.EINVAL);
+ return -1;
}
try {
FS.mknod(path, mode, dev);
@@ -4273,9 +4279,11 @@ LibraryManager.library = {
__cxa_guard_release: function() {},
__cxa_guard_abort: function() {},
+#if USE_TYPED_ARRAYS != 2
_ZTVN10__cxxabiv119__pointer_type_infoE: [0], // is a pointer
_ZTVN10__cxxabiv117__class_type_infoE: [1], // no inherited classes
_ZTVN10__cxxabiv120__si_class_type_infoE: [2], // yes inherited classes
+#endif
// Exceptions
__cxa_allocate_exception: function(size) {
@@ -4657,20 +4665,28 @@ LibraryManager.library = {
cos: 'Math.cos',
cosf: 'Math.cos',
+ cosl: 'Math.cos',
sin: 'Math.sin',
sinf: 'Math.sin',
+ sinl: 'Math.sin',
tan: 'Math.tan',
tanf: 'Math.tan',
+ tanl: 'Math.tan',
acos: 'Math.acos',
acosf: 'Math.acos',
+ acosl: 'Math.acos',
asin: 'Math.asin',
asinf: 'Math.asin',
+ asinl: 'Math.asin',
atan: 'Math.atan',
atanf: 'Math.atan',
+ atanl: 'Math.atan',
atan2: 'Math.atan2',
atan2f: 'Math.atan2',
+ atan2l: 'Math.atan2',
exp: 'Math.exp',
expf: 'Math.exp',
+ expl: 'Math.exp',
// The erf and erfc functions are inspired from
// http://www.digitalmars.com/archives/cplusplus/3634.html
@@ -4706,7 +4722,8 @@ LibraryManager.library = {
} while (Math.abs(q1 - q2) / q2 > MATH_TOLERANCE);
return (ONE_SQRTPI * Math.exp(- x * x) * q2);
},
- erfcf: 'erfcf',
+ erfcf: 'erfc',
+ erfcl: 'erfc',
erf__deps: ['erfc'],
erf: function(x) {
var MATH_TOLERANCE = 1E-12;
@@ -4730,18 +4747,25 @@ LibraryManager.library = {
return (TWO_SQRTPI * sum);
},
erff: 'erf',
+ erfl: 'erf',
log: 'Math.log',
logf: 'Math.log',
+ logl: 'Math.log',
sqrt: 'Math.sqrt',
sqrtf: 'Math.sqrt',
+ sqrtl: 'Math.sqrt',
fabs: 'Math.abs',
fabsf: 'Math.abs',
+ fabsl: 'Math.abs',
ceil: 'Math.ceil',
ceilf: 'Math.ceil',
+ ceill: 'Math.ceil',
floor: 'Math.floor',
floorf: 'Math.floor',
+ floorl: 'Math.floor',
pow: 'Math.pow',
powf: 'Math.pow',
+ powl: 'Math.pow',
llvm_sqrt_f32: 'Math.sqrt',
llvm_sqrt_f64: 'Math.sqrt',
llvm_pow_f32: 'Math.pow',
@@ -4812,6 +4836,7 @@ LibraryManager.library = {
return __reallyNegative(a) === __reallyNegative(b) ? a : -a;
},
copysignf: 'copysign',
+ copysignl: 'copysign',
__signbit__deps: ['copysign'],
__signbit: function(x) {
// We implement using copysign so that we get support
@@ -4824,56 +4849,70 @@ LibraryManager.library = {
return Math.sqrt(a*a + b*b);
},
hypotf: 'hypot',
+ hypotl: 'hypot',
sinh: function(x) {
var p = Math.pow(Math.E, x);
return (p - (1 / p)) / 2;
},
sinhf: 'sinh',
+ sinhl: 'sinh',
cosh: function(x) {
var p = Math.pow(Math.E, x);
return (p + (1 / p)) / 2;
},
coshf: 'cosh',
+ coshl: 'cosh',
tanh__deps: ['sinh', 'cosh'],
tanh: function(x) {
return _sinh(x) / _cosh(x);
},
tanhf: 'tanh',
+ tanhl: 'tanh',
asinh: function(x) {
return Math.log(x + Math.sqrt(x * x + 1));
},
asinhf: 'asinh',
+ asinhl: 'asinh',
acosh: function(x) {
return Math.log(x * 1 + Math.sqrt(x * x - 1));
},
acoshf: 'acosh',
+ acoshl: 'acosh',
atanh: function(x) {
return Math.log((1 + x) / (1 - x)) / 2;
},
atanhf: 'atanh',
+ atanhl: 'atanh',
exp2: function(x) {
return Math.pow(2, x);
},
exp2f: 'exp2',
+ exp2l: 'exp2',
expm1: function(x) {
return Math.exp(x) - 1;
},
expm1f: 'expm1',
+ expm1l: 'expm1',
round: function(x) {
return (x < 0) ? -Math.round(-x) : Math.round(x);
},
roundf: 'round',
+ roundl: 'round',
lround: 'round',
lroundf: 'round',
+ lroundl: 'round',
llround: 'round',
llroundf: 'round',
+ llroundl: 'round',
rint: function(x) {
if (Math.abs(x % 1) !== 0.5) return Math.round(x);
return x + x % 2 + ((x < 0) ? 1 : -1);
},
rintf: 'rint',
+ rintl: 'rint',
lrint: 'rint',
lrintf: 'rint',
+ lrintl: 'rint',
#if USE_TYPED_ARRAYS == 2
llrint: function(x) {
x = (x < 0) ? -Math.round(-x) : Math.round(x);
@@ -4883,50 +4922,63 @@ LibraryManager.library = {
llrint: 'rint',
#endif
llrintf: 'llrint',
+ llrintl: 'llrint',
nearbyint: 'rint',
nearbyintf: 'rint',
+ nearbyintl: 'rint',
trunc: function(x) {
return (x < 0) ? Math.ceil(x) : Math.floor(x);
},
truncf: 'trunc',
+ truncl: 'trunc',
fdim: function(x, y) {
return (x > y) ? x - y : 0;
},
fdimf: 'fdim',
+ fdiml: 'fdim',
fmax: function(x, y) {
return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y);
},
fmaxf: 'fmax',
+ fmaxl: 'fmax',
fmin: function(x, y) {
return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y);
},
fminf: 'fmin',
+ fminl: 'fmin',
fma: function(x, y, z) {
return x * y + z;
},
fmaf: 'fma',
+ fmal: 'fma',
fmod: function(x, y) {
return x % y;
},
fmodf: 'fmod',
+ fmodl: 'fmod',
remainder: 'fmod',
remainderf: 'fmod',
+ remainderl: 'fmod',
log10: function(x) {
return Math.log(x) / Math.LN10;
},
log10f: 'log10',
+ log10l: 'log10',
log1p: function(x) {
return Math.log(1 + x);
},
log1pf: 'log1p',
+ log1pl: 'log1p',
log2: function(x) {
return Math.log(x) / Math.LN2;
},
log2f: 'log2',
+ log2l: 'log2',
nan: function(x) {
return NaN;
},
nanf: 'nan',
+ nanl: 'nan',
sincos: function(x, sine, cosine) {
var sineVal = Math.sin(x),
@@ -4934,6 +4986,7 @@ LibraryManager.library = {
{{{ makeSetValue('sine', '0', 'sineVal', 'double') }}};
{{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}};
},
+ sincosl: 'sincos',
sincosf: function(x, sine, cosine) {
var sineVal = Math.sin(x),
@@ -5012,24 +5065,74 @@ 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 ASM_JS
+#if DLOPEN_SUPPORT == 0
+ abort('need to build with DLOPEN_SUPPORT=1 to get dlopen support in asm.js');
+#endif
+#endif
+
+ 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;
}
@@ -5040,7 +5143,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);
@@ -5048,19 +5151,26 @@ LibraryManager.library = {
}
try {
- var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length);
+ var lib_module = eval(lib_data)(
+#if ASM_JS
+ DLFCN.functionTable.length,
+#else
+ {{{ Functions.getTable('x') }}}.length,
+#endif
+ Module
+ );
} catch (e) {
#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.
@@ -5074,60 +5184,66 @@ 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) {
- delete DLFCN_DATA.loadedLibNames[lib_record.name];
- delete DLFCN_DATA.loadedLibs[handle];
+ if (lib_record.module.cleanups) {
+ lib_record.module.cleanups.forEach(function(cleanup) { cleanup() });
+ }
+ 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 {
var result = lib.module[symbol];
if (typeof result == 'function') {
- {{{ Functions.getTable('x') }}}.push(result);
- {{{ Functions.getTable('x') }}}.push(0);
- result = {{{ Functions.getTable('x') }}}.length - 2;
+#if ASM_JS
+ result = lib.module.SYMBOL_TABLE[symbol];
+ assert(result);
+#else
+ result = Runtime.addFunction(result);
+#endif
lib.cached_functions = result;
}
return result;
@@ -5136,18 +5252,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;
}
},
@@ -5227,8 +5343,8 @@ LibraryManager.library = {
['i32', 'tm_zone']]),
// Statically allocated time struct.
__tm_current: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)',
- // Statically allocated timezone strings.
- __tm_timezones: {},
+ // Statically allocated timezone string. We only use GMT as a timezone.
+ __tm_timezone: 'allocate(intArrayFromString("GMT"), "i8", ALLOC_STATIC)',
// Statically allocated time strings.
__tm_formatted: 'allocate({{{ Runtime.QUANTUM_SIZE }}}*26, "i8", ALLOC_STATIC)',
@@ -5256,7 +5372,7 @@ LibraryManager.library = {
return _gmtime_r(time, ___tm_current);
},
- gmtime_r__deps: ['__tm_struct_layout', '__tm_timezones'],
+ gmtime_r__deps: ['__tm_struct_layout', '__tm_timezone'],
gmtime_r: function(time, tmPtr) {
var date = new Date({{{ makeGetValue('time', 0, 'i32') }}}*1000);
var offsets = ___tm_struct_layout;
@@ -5278,12 +5394,7 @@ LibraryManager.library = {
start.setUTCMilliseconds(0);
var yday = Math.floor((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
{{{ makeSetValue('tmPtr', 'offsets.tm_yday', 'yday', 'i32') }}}
-
- var timezone = "GMT";
- if (!(timezone in ___tm_timezones)) {
- ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
- }
- {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
+ {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}}
return tmPtr;
},
@@ -5302,7 +5413,7 @@ LibraryManager.library = {
return _localtime_r(time, ___tm_current);
},
- localtime_r__deps: ['__tm_struct_layout', '__tm_timezones', 'tzset'],
+ localtime_r__deps: ['__tm_struct_layout', '__tm_timezone', 'tzset'],
localtime_r: function(time, tmPtr) {
_tzset();
var offsets = ___tm_struct_layout;
@@ -5323,11 +5434,7 @@ LibraryManager.library = {
var dst = Number(start.getTimezoneOffset() != date.getTimezoneOffset());
{{{ makeSetValue('tmPtr', 'offsets.tm_isdst', 'dst', 'i32') }}}
- var timezone = 'GMT'; // XXX do not rely on browser timezone info, it is very unpredictable | date.toString().match(/\(([A-Z]+)\)/)[1];
- if (!(timezone in ___tm_timezones)) {
- ___tm_timezones[timezone] = allocate(intArrayFromString(timezone), 'i8', ALLOC_NORMAL);
- }
- {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezones[timezone]', 'i32') }}}
+ {{{ makeSetValue('tmPtr', 'offsets.tm_zone', '___tm_timezone', 'i32') }}}
return tmPtr;
},
@@ -6009,7 +6116,7 @@ LibraryManager.library = {
// int clock_gettime(clockid_t clk_id, struct timespec *tp);
var now = Date.now();
{{{ makeSetValue('tp', '___timespec_struct_layout.tv_sec', 'Math.floor(now/1000)', 'i32') }}}; // seconds
- {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}; // nanoseconds - not supported
+ {{{ makeSetValue('tp', '___timespec_struct_layout.tv_nsec', '(now % 1000) * 1000 * 1000', 'i32') }}}; // nanoseconds (really milliseconds)
return 0;
},
clock_settime: function(clk_id, tp) {
@@ -6021,7 +6128,7 @@ LibraryManager.library = {
clock_getres: function(clk_id, res) {
// int clock_getres(clockid_t clk_id, struct timespec *res);
{{{ makeSetValue('res', '___timespec_struct_layout.tv_sec', '1', 'i32') }}}
- {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '0', 'i32') }}}
+ {{{ makeSetValue('res', '___timespec_struct_layout.tv_nsec', '1000 * 1000', 'i32') }}} // resolution is milliseconds
return 0;
},
@@ -7193,7 +7300,25 @@ LibraryManager.library = {
}
},
+ // ==========================================================================
+ // net/if.h
+ // ==========================================================================
+
+ if_nametoindex: function(a) {
+ return 0;
+ },
+ if_indextoname: function(a, b) {
+ return 0;
+ },
+ if_nameindex: function() {
+ return 0;
+ },
+ if_freenameindex: function(a) {
+ },
+
+ // ==========================================================================
// netinet/in.h
+ // ==========================================================================
_in6addr_any:
'allocate([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], "i8", ALLOC_STATIC)',
@@ -7312,7 +7437,7 @@ LibraryManager.library = {
var aliasesBuf = _malloc(4);
{{{ makeSetValue('aliasesBuf', '0', '0', 'i8*') }}}
{{{ makeSetValue('ret', '___hostent_struct_layout.h_aliases', 'aliasesBuf', 'i8**') }}}
- var afinet = {{{ cDefine("AF_INET") }}};
+ var afinet = {{{ cDefine('AF_INET') }}};
{{{ makeSetValue('ret', '___hostent_struct_layout.h_addrtype', 'afinet', 'i32') }}}
{{{ makeSetValue('ret', '___hostent_struct_layout.h_length', '4', 'i32') }}}
var addrListBuf = _malloc(12);
diff --git a/src/library_fs.js b/src/library_fs.js
index 5573dc27..4a150d80 100644
--- a/src/library_fs.js
+++ b/src/library_fs.js
@@ -14,11 +14,10 @@ mergeInto(LibraryManager.library, {
'Module["FS_createDevice"] = FS.createDevice;',
$FS: {
root: null,
- nodes: [null],
devices: [null],
streams: [null],
nextInode: 1,
- name_table: null,
+ nameTable: null,
currentPath: '/',
initialized: false,
// Whether we are currently ignoring permissions. Useful when preparing the
@@ -49,6 +48,76 @@ mergeInto(LibraryManager.library, {
},
//
+ // paths
+ //
+ cwd: function() {
+ return FS.currentPath;
+ },
+ lookupPath: function(path, opts) {
+ path = PATH.resolve(FS.currentPath, path);
+ opts = opts || { recurse_count: 0 };
+
+ if (opts.recurse_count > 8) { // max recursive lookup of 8
+ throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+ }
+
+ // split the path
+ var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
+ return !!p;
+ }), false);
+
+ // start at the root
+ var current = FS.root;
+ var current_path = '/';
+
+ for (var i = 0; i < parts.length; i++) {
+ var islast = (i === parts.length-1);
+ if (islast && opts.parent) {
+ // stop resolving
+ break;
+ }
+
+ current = FS.lookupNode(current, parts[i]);
+ current_path = PATH.join(current_path, parts[i]);
+
+ // jump to the mount's root node if this is a mountpoint
+ if (FS.isMountpoint(current)) {
+ current = current.mount.root;
+ }
+
+ // follow symlinks
+ // by default, lookupPath will not follow a symlink if it is the final path component.
+ // setting opts.follow = true will override this behavior.
+ if (!islast || opts.follow) {
+ var count = 0;
+ while (FS.isLink(current.mode)) {
+ var link = FS.readlink(current_path);
+ current_path = PATH.resolve(PATH.dirname(current_path), link);
+
+ var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
+ current = lookup.node;
+
+ if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
+ throw new FS.ErrnoError(ERRNO_CODES.ELOOP);
+ }
+ }
+ }
+ }
+
+ return { path: current_path, node: current };
+ },
+ getPath: function(node) {
+ var path;
+ while (true) {
+ if (FS.isRoot(node)) {
+ return path ? PATH.join(node.mount.mountpoint, path) : node.mount.mountpoint;
+ }
+ path = path ? PATH.join(node.name, path) : node.name;
+ node = node.parent;
+ }
+ },
+
+ //
// nodes
//
hashName: function(parentid, name) {
@@ -56,19 +125,19 @@ mergeInto(LibraryManager.library, {
for (var i = 0; i < name.length; i++) {
hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
}
- return ((parentid + hash) >>> 0) % FS.name_table.length;
+ return ((parentid + hash) >>> 0) % FS.nameTable.length;
},
hashAddNode: function(node) {
var hash = FS.hashName(node.parent.id, node.name);
- node.name_next = FS.name_table[hash];
- FS.name_table[hash] = node;
+ node.name_next = FS.nameTable[hash];
+ FS.nameTable[hash] = node;
},
hashRemoveNode: function(node