diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 43 | ||||
-rw-r--r-- | src/embind/embind.js | 26 | ||||
-rw-r--r-- | src/embind/emval.js | 15 | ||||
-rw-r--r-- | src/intertyper.js | 2 | ||||
-rw-r--r-- | src/jsifier.js | 34 | ||||
-rw-r--r-- | src/library.js | 646 | ||||
-rw-r--r-- | src/library_browser.js | 31 | ||||
-rw-r--r-- | src/library_gl.js | 10 | ||||
-rw-r--r-- | src/library_sdl.js | 132 | ||||
-rw-r--r-- | src/modules.js | 19 | ||||
-rw-r--r-- | src/parseTools.js | 10 | ||||
-rw-r--r-- | src/preamble.js | 3 | ||||
-rw-r--r-- | src/relooper/Relooper.cpp | 2 | ||||
-rw-r--r-- | src/runtime.js | 14 | ||||
-rw-r--r-- | src/settings.js | 12 | ||||
-rw-r--r-- | src/shell.js | 80 |
16 files changed, 809 insertions, 270 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index de9a7940..b1f0b585 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -502,18 +502,38 @@ function analyzer(data, sidePass) { { intertype: 'value', ident: j.toString(), type: 'i32' } ] }); - var actualSizeType = 'i' + element.bits; // The last one may be smaller than 32 bits - toAdd.push({ + var newItem = { intertype: 'load', assignTo: element.ident, - pointerType: actualSizeType + '*', - valueType: actualSizeType, - type: actualSizeType, // XXX why is this missing from intertyper? - pointer: { intertype: 'value', ident: tempVar, type: actualSizeType + '*' }, + pointerType: 'i32*', + valueType: 'i32', + type: 'i32', + pointer: { intertype: 'value', ident: tempVar, type: 'i32*' }, ident: tempVar, - pointerType: actualSizeType + '*', align: value.align - }); + }; + var newItem2 = null; + // The last one may be smaller than 32 bits + if (element.bits < 32) { + newItem.assignTo += '$preadd$'; + newItem2 = { + intertype: 'mathop', + op: 'and', + assignTo: element.ident, + type: 'i32', + params: [{ + intertype: 'value', + type: 'i32', + ident: newItem.assignTo + }, { + intertype: 'value', + type: 'i32', + ident: (0xffffffff >>> (32 - element.bits)).toString() + }], + }; + } + toAdd.push(newItem); + if (newItem2) toAdd.push(newItem2); j++; }); Types.needAnalysis['[0 x i32]'] = 0; @@ -1433,15 +1453,14 @@ function analyzer(data, sidePass) { func.labelsDict = {}; func.labelIds = {}; func.labelIdsInverse = {}; - func.labelIds[toNiceIdent('%0')] = 1; - func.labelIdsInverse[0] = toNiceIdent('%0'); - func.labelIdCounter = 2; + func.labelIdCounter = 1; func.labels.forEach(function(label) { if (!(label.ident in func.labelIds)) { func.labelIds[label.ident] = func.labelIdCounter++; func.labelIdsInverse[func.labelIdCounter-1] = label.ident; } }); + var entryIdent = func.labels[0].ident; // Minify label ids to numeric ids. func.labels.forEach(function(label) { @@ -1478,7 +1497,7 @@ function analyzer(data, sidePass) { function getActualLabelId(labelId) { if (func.labelsDict[labelId]) return labelId; // If not present, it must be a surprisingly-named entry (or undefined behavior, in which case, still ok to use the entry) - labelId = func.labelIds[ENTRY_IDENT]; + labelId = func.labelIds[entryIdent]; assert(func.labelsDict[labelId]); return labelId; } diff --git a/src/embind/embind.js b/src/embind/embind.js index 91386c69..f0cd0c74 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -5,9 +5,9 @@ /*global __emval_register, _emval_handle_array, __emval_decref*/ /*global ___getTypeName*/ /*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ -var InternalError = Module.InternalError = extendError(Error, 'InternalError'); -var BindingError = Module.BindingError = extendError(Error, 'BindingError'); -var UnboundTypeError = Module.UnboundTypeError = extendError(BindingError, 'UnboundTypeError'); +var InternalError = Module['InternalError'] = extendError(Error, 'InternalError'); +var BindingError = Module['BindingError'] = extendError(Error, 'BindingError'); +var UnboundTypeError = Module['UnboundTypeError'] = extendError(BindingError, 'UnboundTypeError'); function throwInternalError(message) { throw new InternalError(message); @@ -638,7 +638,7 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, var tupleRegistrations = {}; -function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { +function __embind_register_value_array(rawType, name, rawConstructor, rawDestructor) { tupleRegistrations[rawType] = { name: readLatin1String(name), rawConstructor: FUNCTION_TABLE[rawConstructor], @@ -647,7 +647,7 @@ function __embind_register_tuple(rawType, name, rawConstructor, rawDestructor) { }; } -function __embind_register_tuple_element( +function __embind_register_value_array_element( rawTupleType, getterReturnType, getter, @@ -666,7 +666,7 @@ function __embind_register_tuple_element( }); } -function __embind_finalize_tuple(rawTupleType) { +function __embind_finalize_value_array(rawTupleType) { var reg = tupleRegistrations[rawTupleType]; delete tupleRegistrations[rawTupleType]; var elements = reg.elements; @@ -725,7 +725,7 @@ function __embind_finalize_tuple(rawTupleType) { var structRegistrations = {}; -function __embind_register_struct( +function __embind_register_value_object( rawType, name, rawConstructor, @@ -739,7 +739,7 @@ function __embind_register_struct( }; } -function __embind_register_struct_field( +function __embind_register_value_object_field( structType, fieldName, getterReturnType, @@ -760,7 +760,7 @@ function __embind_register_struct_field( }); } -function __embind_finalize_struct(structType) { +function __embind_finalize_value_object(structType) { var reg = structRegistrations[structType]; delete structRegistrations[structType]; @@ -879,11 +879,11 @@ var genericPointerToWireType = function(destructors, handle) { if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { - var clonedHandle = handle.clone(); + var clonedHandle = handle['clone'](); ptr = this.rawShare( ptr, __emval_register(function() { - clonedHandle.delete(); + clonedHandle['delete'](); }) ); if (destructors !== null) { @@ -1088,7 +1088,7 @@ function getInstanceTypeName(handle) { return handle.$$.ptrType.registeredClass.name; } -ClassHandle.prototype.isAliasOf = function(other) { +ClassHandle.prototype['isAliasOf'] = function(other) { if (!(this instanceof ClassHandle)) { return false; } @@ -1118,7 +1118,7 @@ function throwInstanceAlreadyDeleted(obj) { throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); } -ClassHandle.prototype.clone = function() { +ClassHandle.prototype['clone'] = function() { if (!this.$$.ptr) { throwInstanceAlreadyDeleted(this); } diff --git a/src/embind/emval.js b/src/embind/emval.js index 77270597..0d075188 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -4,6 +4,7 @@ /*global createNamedFunction*/ /*global readLatin1String, writeStringToMemory*/ /*global requireRegisteredType, throwBindingError*/ +/*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ var Module = Module || {}; @@ -100,7 +101,7 @@ function __emval_new_cstring(v) { function __emval_take_value(type, v) { type = requireRegisteredType(type, '_emval_take_value'); - v = type.fromWireType(v); + v = type['fromWireType'](v); return __emval_register(v); } @@ -203,7 +204,7 @@ function __emval_as(handle, returnType) { returnType = requireRegisteredType(returnType, 'emval::as'); var destructors = []; // caller owns destructing - return returnType.toWireType(destructors, _emval_handle_array[handle].value); + return returnType['toWireType'](destructors, _emval_handle_array[handle].value); } function parseParameters(argCount, argTypes, argWireTypes) { @@ -212,7 +213,7 @@ function parseParameters(argCount, argTypes, argWireTypes) { var argType = requireRegisteredType( HEAP32[(argTypes >> 2) + i], "parameter " + i); - a[i] = argType.fromWireType(argWireTypes[i]); + a[i] = argType['fromWireType'](argWireTypes[i]); } return a; } @@ -223,7 +224,7 @@ function __emval_call(handle, argCount, argTypes) { var args = new Array(argCount); for (var i = 0; i < argCount; ++i) { - args[i] = types[i].fromWireType(arguments[3 + i]); + args[i] = types[i]['fromWireType'](arguments[3 + i]); } var fn = _emval_handle_array[handle].value; @@ -247,8 +248,8 @@ function __emval_get_method_caller(argCount, argTypes) { var retType = types[0]; var signatureName = retType.name + "_$" + types.slice(1).map(function (t) { return t.name; }).join("_") + "$"; - var args1 = ["Runtime", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"]; - var args2 = [Runtime, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType]; + var args1 = ["addFunction", "createNamedFunction", "requireHandle", "getStringOrSymbol", "_emval_handle_array", "retType"]; + var args2 = [Runtime.addFunction, createNamedFunction, requireHandle, getStringOrSymbol, _emval_handle_array, retType]; var argsList = ""; // 'arg0, arg1, arg2, ... , argN' var argsListWired = ""; // 'arg0Wired, ..., argNWired' @@ -260,7 +261,7 @@ function __emval_get_method_caller(argCount, argTypes) { } var invokerFnBody = - "return Runtime.addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" + + "return addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" + "requireHandle(handle);\n" + "name = getStringOrSymbol(name);\n"; diff --git a/src/intertyper.js b/src/intertyper.js index 94d937e1..abfbdacb 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -503,6 +503,7 @@ function intertyper(data, sidePass, baseLineNums) { // variable var ident = item.tokens[0].text; var private_ = findTokenText(item, 'private') >= 0 || findTokenText(item, 'internal') >= 0; + var named = findTokenText(item, 'unnamed_addr') < 0; cleanOutTokens(LLVM.GLOBAL_MODIFIERS, item.tokens, [2, 3]); var external = false; if (item.tokens[2].text === 'external') { @@ -516,6 +517,7 @@ function intertyper(data, sidePass, baseLineNums) { type: item.tokens[2].text, external: external, private_: private_, + named: named, lineNum: item.lineNum }; if (!NAMED_GLOBALS) { diff --git a/src/jsifier.js b/src/jsifier.js index 82b78d0a..b377202d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -286,6 +286,8 @@ function JSify(data, functionsOnly, givenFunctions) { allocator = 'ALLOC_NONE'; } + Variables.globals[item.ident].named = item.named; + if (ASM_JS && (MAIN_MODULE || SIDE_MODULE) && !item.private_ && !NAMED_GLOBALS && isIndexableGlobal(item.ident)) { // We need this to be named (and it normally would not be), so that it can be linked to and used from other modules Variables.globals[item.ident].linkable = 1; @@ -602,6 +604,8 @@ function JSify(data, functionsOnly, givenFunctions) { var associatedSourceFile = "NO_SOURCE"; } + if (DLOPEN_SUPPORT) Functions.getIndex(func.ident); + func.JS += 'function ' + func.ident + '(' + paramIdents.join(', ') + ') {\n'; if (PGO) { @@ -1207,7 +1211,7 @@ function JSify(data, functionsOnly, givenFunctions) { // in an assignment var disabled = DISABLE_EXCEPTION_CATCHING == 2 && !(item.funcData.ident in EXCEPTION_CATCHING_WHITELIST); var phiSets = calcPhiSets(item); - var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone); + var call_ = makeFunctionCall(item.ident, item.params, item.funcData, item.type, ASM_JS && !disabled, !!item.assignTo || !item.standalone, true); var ret; @@ -1364,7 +1368,7 @@ function JSify(data, functionsOnly, givenFunctions) { return ret; }); - function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn) { + function makeFunctionCall(ident, params, funcData, type, forceByPointer, hasReturn, invoke) { // We cannot compile assembly. See comment in intertyper.js:'Call' assert(ident != 'asm', 'Inline assembly cannot be compiled to JavaScript!'); @@ -1429,7 +1433,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 || funcData.setjmpTable) { + if (shortident in Functions.libraryFunctions || simpleIdent in Functions.libraryFunctions || byPointerForced || invoke || 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]) }); @@ -1470,7 +1474,6 @@ function JSify(data, functionsOnly, givenFunctions) { } args = args.concat(varargs); - var argsText = args.join(', '); // Inline if either we inline whenever we can (and we can), or if there is no noninlined version var inline = LibraryManager.library[simpleIdent + '__inline']; @@ -1492,16 +1495,35 @@ function JSify(data, functionsOnly, givenFunctions) { } } + if (callIdent in Functions.implementedFunctions) { + // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as. + var numArgs = Functions.implementedFunctions[callIdent].length - 1; + if (numArgs !== args.length) { + if (VERBOSE) warnOnce('Fixing function call arguments based on signature, on ' + [callIdent, args.length, numArgs]); + while (args.length > numArgs) { args.pop(); argsTypes.pop() } + while (args.length < numArgs) { args.push('0'); argsTypes.push('i32') } + } + } + var returnType = 'void'; if ((byPointer || ASM_JS) && hasReturn) { returnType = getReturnType(type); + if (callIdent in Functions.implementedFunctions) { + // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as + var trueType = Functions.getSignatureReturnType(Functions.implementedFunctions[callIdent]); + if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) { + if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]); + returnType = trueType; + } + } } if (byPointer) { var sig = Functions.getSignature(returnType, argsTypes, hasVarArgs); if (ASM_JS) { assert(returnType.search(/\("'\[,/) == -1); // XXX need isFunctionType(type, out) - if (!byPointerForced && !funcData.setjmpTable) { + var functionTableCall = !byPointerForced && !funcData.setjmpTable && !invoke; + if (functionTableCall) { // normal asm function pointer call callIdent = '(' + callIdent + ')&{{{ FTM_' + sig + ' }}}'; // the function table mask is set in emscripten.py Functions.neededTables[sig] = 1; @@ -1516,7 +1538,7 @@ function JSify(data, functionsOnly, givenFunctions) { assert(!ASM_JS, 'cannot emit safe dyncalls in asm'); callIdent = '(tempInt=' + callIdent + ',tempInt < 0 || tempInt >= FUNCTION_TABLE.length-1 || !FUNCTION_TABLE[tempInt] ? abort("dyncall error: ' + sig + ' " + FUNCTION_TABLE_NAMES[tempInt]) : tempInt)'; } - if (!ASM_JS || (!byPointerForced && !funcData.setjmpTable)) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; + if (!ASM_JS || functionTableCall) callIdent = Functions.getTable(sig) + '[' + callIdent + ']'; } var ret = callIdent + '(' + args.join(', ') + ')'; diff --git a/src/library.js b/src/library.js index c5618b53..e650a545 100644 --- a/src/library.js +++ b/src/library.js @@ -559,25 +559,28 @@ LibraryManager.library = { }; } var utf8 = new Runtime.UTF8Processor(); - function simpleOutput(val) { - if (val === null || val === {{{ charCode('\n') }}}) { - output.printer(output.buffer.join('')); - output.buffer = []; - } else { - output.buffer.push(utf8.processCChar(val)); - } + function createSimpleOutput() { + var fn = function (val) { + if (val === null || val === {{{ charCode('\n') }}}) { + fn.printer(fn.buffer.join('')); + fn.buffer = []; + } else { + fn.buffer.push(utf8.processCChar(val)); + } + }; + return fn; } if (!output) { stdoutOverridden = false; - output = simpleOutput; + output = createSimpleOutput(); } if (!output.printer) output.printer = Module['print']; if (!output.buffer) output.buffer = []; if (!error) { stderrOverridden = false; - error = simpleOutput; + error = createSimpleOutput(); } - if (!error.printer) error.printer = Module['print']; + if (!error.printer) error.printer = Module['printErr']; if (!error.buffer) error.buffer = []; // Create the temporary folder, if not already created @@ -1045,27 +1048,45 @@ LibraryManager.library = { mknod: function(path, mode, dev) { // int mknod(const char *path, mode_t mode, dev_t dev); // http://pubs.opengroup.org/onlinepubs/7908799/xsh/mknod.html - if (dev !== 0 || !(mode & 0xC000)) { // S_IFREG | S_IFDIR. - // Can't create devices or pipes through mknod(). + path = Pointer_stringify(path); + var fmt = (mode & {{{ cDefine('S_IFMT') }}}); + if (fmt !== {{{ cDefine('S_IFREG') }}} && fmt !== {{{ cDefine('S_IFCHR') }}} && + fmt !== {{{ cDefine('S_IFBLK') }}} && fmt !== {{{ cDefine('S_IFIFO') }}} && + fmt !== {{{ cDefine('S_IFSOCK') }}}) { + // not valid formats for mknod ___setErrNo(ERRNO_CODES.EINVAL); return -1; - } else { - var properties = {contents: [], isFolder: Boolean(mode & 0x4000)}; // S_IFDIR. - path = FS.analyzePath(Pointer_stringify(path)); - try { - FS.createObject(path.parentObject, path.name, properties, - mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR. - return 0; - } catch (e) { - return -1; - } + } + if (fmt === {{{ cDefine('S_IFCHR') }}} || fmt === {{{ cDefine('S_IFBLK') }}} || + fmt === {{{ cDefine('S_IFIFO') }}} || fmt === {{{ cDefine('S_IFSOCK') }}}) { + // not supported currently + ___setErrNo(ERRNO_CODES.EPERM); + return -1; + } + path = FS.analyzePath(path); + var properties = { contents: [], isFolder: false }; // S_IFDIR. + try { + FS.createObject(path.parentObject, path.name, properties, + mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR. + return 0; + } catch (e) { + return -1; } }, mkdir__deps: ['mknod'], mkdir: function(path, mode) { // int mkdir(const char *path, mode_t mode); // http://pubs.opengroup.org/onlinepubs/7908799/xsh/mkdir.html - return _mknod(path, 0x4000 | (mode & 0x180), 0); // S_IFDIR, S_IRUSR | S_IWUSR. + path = Pointer_stringify(path); + path = FS.analyzePath(path); + var properties = { contents: [], isFolder: true }; + try { + FS.createObject(path.parentObject, path.name, properties, + mode & 0x100, mode & 0x80); // S_IRUSR, S_IWUSR. + return 0; + } catch (e) { + return -1; + } }, mkfifo__deps: ['__setErrNo', '$ERRNO_CODES'], mkfifo: function(path, mode) { @@ -1079,10 +1100,13 @@ LibraryManager.library = { return -1; }, chmod__deps: ['$FS'], - chmod: function(path, mode) { + chmod: function(path, mode, dontResolveLastLink) { // int chmod(const char *path, mode_t mode); // http://pubs.opengroup.org/onlinepubs/7908799/xsh/chmod.html - var obj = FS.findObject(Pointer_stringify(path)); + // NOTE: dontResolveLastLink is a shortcut for lchmod(). It should never be + // used in client code. + path = typeof path !== 'string' ? Pointer_stringify(path) : path; + var obj = FS.findObject(path, dontResolveLastLink); if (obj === null) return -1; obj.read = mode & 0x100; // S_IRUSR. obj.write = mode & 0x80; // S_IWUSR. @@ -1093,15 +1117,16 @@ LibraryManager.library = { fchmod: function(fildes, mode) { // int fchmod(int fildes, mode_t mode); // http://pubs.opengroup.org/onlinepubs/7908799/xsh/fchmod.html - if (!FS.streams[fildes]) { + var stream = FS.streams[fildes]; + if (!stream) { ___setErrNo(ERRNO_CODES.EBADF); return -1; - } else { - var pathArray = intArrayFromString(FS.streams[fildes].path); - return _chmod(allocate(pathArray, 'i8', ALLOC_STACK), mode); } + return _chmod(stream.path, mode); + }, + lchmod: function(path, mode) { + return _chmod(path, mode, true); }, - lchmod: function() { throw 'TODO: lchmod' }, umask__deps: ['$FS'], umask: function(newMask) { @@ -1115,6 +1140,7 @@ LibraryManager.library = { }, stat64: 'stat', fstat64: 'fstat', + lstat64: 'lstat', __01fstat64_: 'fstat', __01stat64_: 'stat', __01lstat64_: 'lstat', @@ -1775,6 +1801,8 @@ LibraryManager.library = { } else if (nbyte < 0 || offset < 0) { ___setErrNo(ERRNO_CODES.EINVAL); return -1; + } else if (offset >= stream.object.contents.length) { + return 0; } else { var bytesRead = 0; while (stream.ungotten.length && nbyte > 0) { @@ -1784,6 +1812,8 @@ LibraryManager.library = { } var contents = stream.object.contents; var size = Math.min(contents.length - offset, nbyte); + assert(size >= 0); + #if USE_TYPED_ARRAYS == 2 if (contents.subarray) { // typed array HEAPU8.set(contents.subarray(offset, offset+size), buf); @@ -1851,6 +1881,7 @@ LibraryManager.library = { } else { var ungotSize = stream.ungotten.length; bytesRead = _pread(fildes, buf, nbyte, stream.position); + assert(bytesRead >= -1); if (bytesRead != -1) { stream.position += (stream.ungotten.length - ungotSize) + bytesRead; } @@ -1867,42 +1898,42 @@ LibraryManager.library = { rmdir: function(path) { // int rmdir(const char *path); // http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html - path = FS.analyzePath(Pointer_stringify(path)); + path = Pointer_stringify(path); + path = FS.analyzePath(path, true); if (!path.parentExists || !path.exists) { ___setErrNo(path.error); return -1; - } else if (!path.object.write || path.isRoot) { + } else if (!path.parentObject.write) { ___setErrNo(ERRNO_CODES.EACCES); return -1; } else if (!path.object.isFolder) { ___setErrNo(ERRNO_CODES.ENOTDIR); return -1; + } else if (path.isRoot || path.path == FS.currentPath) { + ___setErrNo(ERRNO_CODES.EBUSY); + return -1; } else { for (var i in path.object.contents) { ___setErrNo(ERRNO_CODES.ENOTEMPTY); return -1; } - if (path.path == FS.currentPath) { - ___setErrNo(ERRNO_CODES.EBUSY); - return -1; - } else { - delete path.parentObject.contents[path.name]; - return 0; - } + delete path.parentObject.contents[path.name]; + return 0; } }, unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'], unlink: function(path) { // int unlink(const char *path); // http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html - path = FS.analyzePath(Pointer_stringify(path)); + path = Pointer_stringify(path); + path = FS.analyzePath(path, true); if (!path.parentExists || !path.exists) { ___setErrNo(path.error); return -1; } else if (path.object.isFolder) { - ___setErrNo(ERRNO_CODES.EISDIR); + ___setErrNo(ERRNO_CODES.EPERM); return -1; - } else if (!path.object.write) { + } else if (!path.parentObject.write) { ___setErrNo(ERRNO_CODES.EACCES); return -1; } else { @@ -2559,15 +2590,27 @@ LibraryManager.library = { continue; } - // TODO: Support strings like "%5c" etc. - if (format[formatIndex] === '%' && format[formatIndex+1] == 'c') { - var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; - argIndex += Runtime.getAlignSize('void*', null, true); - fields++; - next = get(); - {{{ makeSetValue('argPtr', 0, 'next', 'i8') }}} - formatIndex += 2; - continue; + if (format[formatIndex] === '%') { + var nextC = format.indexOf('c', formatIndex+1); + if (nextC > 0) { + var maxx = 1; + if (nextC > formatIndex+1) { + var sub = format.substring(formatIndex+1, nextC) + maxx = parseInt(sub); + if (maxx != sub) maxx = 0; + } + if (maxx) { + var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; + argIndex += Runtime.getAlignSize('void*', null, true); + fields++; + for (var i = 0; i < maxx; i++) { + next = get(); + {{{ makeSetValue('argPtr++', 0, 'next', 'i8') }}}; + } + formatIndex += nextC - formatIndex + 1; + continue; + } + } } // remove whitespace @@ -4898,7 +4941,9 @@ LibraryManager.library = { isprint: function(chr) { return 0x1F < chr && chr < 0x7F; }, - isgraph: 'isprint', + isgraph: function(chr) { + return 0x20 < chr && chr < 0x7F; + }, // Lookup tables for glibc ctype implementation. __ctype_b_loc: function() { // http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html @@ -5735,10 +5780,14 @@ LibraryManager.library = { rintf: 'rint', lrint: 'rint', lrintf: 'rint', +#if USE_TYPED_ARRAYS == 2 llrint: function(x) { x = (x < 0) ? -Math.round(-x) : Math.round(x); {{{ makeStructuralReturn(splitI64('x')) }}}; }, +#else + llrint: 'rint', +#endif llrintf: 'llrint', nearbyint: 'rint', nearbyintf: 'rint', @@ -5881,7 +5930,7 @@ LibraryManager.library = { dlopen: function(filename, flag) { // void *dlopen(const char *file, int mode); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html - filename = (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename); + filename = filename === 0 ? '__self__' : (ENV['LD_LIBRARY_PATH'] || '/') + Pointer_stringify(filename); if (DLFCN_DATA.loadedLibNames[filename]) { // Already loaded; increment ref count and return. @@ -5890,48 +5939,55 @@ LibraryManager.library = { return handle; } - var target = FS.findObject(filename); - if (!target || target.isFolder || target.isDevice) { - DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename; - return 0; + if (filename === '__self__') { + var handle = -1; + var lib_module = Module; + var cached_functions = SYMBOL_TABLE; } else { - FS.forceLoadFile(target); - var lib_data = intArrayToString(target.contents); - } + var target = FS.findObject(filename); + if (!target || target.isFolder || target.isDevice) { + DLFCN_DATA.errorMsg = 'Could not find dynamic lib: ' + filename; + return 0; + } else { + FS.forceLoadFile(target); + var lib_data = intArrayToString(target.contents); + } - try { - var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length); - } catch (e) { + try { + var lib_module = eval(lib_data)({{{ Functions.getTable('x') }}}.length); + } catch (e) { #if ASSERTIONS - Module.printErr('Error in loading dynamic library: ' + e); + Module.printErr('Error in loading dynamic library: ' + e); #endif - DLFCN_DATA.errorMsg = 'Could not evaluate dynamic lib: ' + filename; - return 0; - } + DLFCN_DATA.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++; - } + // Not all browsers support Object.keys(). + var handle = 1; + for (var key in DLFCN_DATA.loadedLibs) { + if (DLFCN_DATA.loadedLibs.hasOwnProperty(key)) 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)) { + Module[ident] = lib_module[ident]; + } + } + } + var cached_functions = {}; + } DLFCN_DATA.loadedLibs[handle] = { refcount: 1, name: filename, module: lib_module, - cached_functions: {} + cached_functions: cached_functions }; 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)) { - Module[ident] = lib_module[ident]; - } - } - } - return handle; }, // int dlclose(void* handle); @@ -5944,7 +6000,7 @@ LibraryManager.library = { return 1; } else { var lib_record = DLFCN_DATA.loadedLibs[handle]; - if (lib_record.refcount-- == 0) { + if (--lib_record.refcount == 0) { delete DLFCN_DATA.loadedLibNames[lib_record.name]; delete DLFCN_DATA.loadedLibs[handle]; } @@ -5963,13 +6019,15 @@ LibraryManager.library = { return 0; } else { var lib = DLFCN_DATA.loadedLibs[handle]; - if (!lib.module.hasOwnProperty(symbol)) { - DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol + - '" in dynamic lib: ' + lib.name); - return 0; + // 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.cached_functions.hasOwnProperty(symbol)) { - return lib.cached_functions[symbol]; + if (!lib.module.hasOwnProperty(symbol)) { + DLFCN_DATA.errorMsg = ('Tried to lookup unknown symbol "' + symbol + + '" in dynamic lib: ' + lib.name); + return 0; } else { var result = lib.module[symbol]; if (typeof result == 'function') { @@ -6210,15 +6268,345 @@ LibraryManager.library = { return -1; }, - strftime: function(s, maxsize, format, timeptr) { + _MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + _MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + + _isLeapYear: function(year) { + return year%4 === 0 && (year%100 !== 0 || year%400 === 0); + }, + + _arraySum: function(array, index) { + var sum = 0; + for (var i = 0; i <= index; sum += array[i++]); + return sum; + }, + + _addDays__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP', '_MONTH_DAYS_REGULAR'], + _addDays: function(date, days) { + var newDate = new Date(date.getTime()); + while(days > 0) { + var leap = __isLeapYear(newDate.getFullYear()); + var currentMonth = newDate.getMonth(); + var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth]; + + if (days > daysInCurrentMonth-newDate.getDate()) { + // we spill over to next month + days -= (daysInCurrentMonth-newDate.getDate()+1); + newDate.setDate(1); + if (currentMonth < 11) { + newDate.setMonth(currentMonth+1) + } else { + newDate.setMonth(0); |