diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/determinstic.js | 8 | ||||
-rw-r--r-- | src/embind/embind.js | 99 | ||||
-rw-r--r-- | src/embind/emval.js | 177 | ||||
-rw-r--r-- | src/intertyper.js | 15 | ||||
-rw-r--r-- | src/jsifier.js | 17 | ||||
-rw-r--r-- | src/library.js | 1242 | ||||
-rw-r--r-- | src/library_browser.js | 72 | ||||
-rw-r--r-- | src/library_gc.js | 2 | ||||
-rw-r--r-- | src/library_gl.js | 1492 | ||||
-rw-r--r-- | src/library_glut.js | 10 | ||||
-rw-r--r-- | src/library_sdl.js | 25 | ||||
-rw-r--r-- | src/parseTools.js | 40 | ||||
-rw-r--r-- | src/postamble.js | 2 | ||||
-rw-r--r-- | src/preamble.js | 13 | ||||
-rw-r--r-- | src/relooper/Relooper.cpp | 127 | ||||
-rw-r--r-- | src/relooper/Relooper.h | 7 | ||||
-rw-r--r-- | src/relooper/fuzzer.py | 4 | ||||
-rw-r--r-- | src/relooper/test.cpp | 41 | ||||
-rw-r--r-- | src/relooper/test.txt | 27 | ||||
-rw-r--r-- | src/relooper/test4.txt | 1 | ||||
-rw-r--r-- | src/relooper/test_debug.txt | 76 | ||||
-rw-r--r-- | src/relooper/test_fuzz1.txt | 11 | ||||
-rw-r--r-- | src/relooper/test_fuzz5.txt | 24 | ||||
-rw-r--r-- | src/relooper/test_fuzz6.txt | 1 | ||||
-rwxr-xr-x | src/relooper/testit.sh | 2 | ||||
-rwxr-xr-x | src/relooper/updateit.sh | 2 | ||||
-rw-r--r-- | src/settings.js | 7 | ||||
-rw-r--r-- | src/shell.js | 1 | ||||
-rw-r--r-- | src/socket.io.js | 3870 | ||||
-rw-r--r-- | src/wrtcp.js | 821 |
30 files changed, 7470 insertions, 766 deletions
diff --git a/src/determinstic.js b/src/determinstic.js index 91f98ed9..1ec0bbfe 100644 --- a/src/determinstic.js +++ b/src/determinstic.js @@ -10,3 +10,11 @@ Date.now = function() { }; performance.now = Date.now; +function hashMemory(id) { + var ret = 0; + for (var i = 0; i < HEAPU8.length; i++) { + ret = (ret*17 + HEAPU8[i])|0; + } + print(id + ':' + ret); +} + diff --git a/src/embind/embind.js b/src/embind/embind.js index cadee700..91386c69 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -131,6 +131,7 @@ function extendError(baseErrorType, errorName) { // from https://github.com/imvu/imvujs/blob/master/src/function.js function createNamedFunction(name, body) { + name = makeLegalFunctionName(name); /*jshint evil:true*/ return new Function( "body", @@ -270,6 +271,10 @@ function __embind_register_void(rawType, name) { 'fromWireType': function() { return undefined; }, + 'toWireType': function(destructors, o) { + // TODO: assert if anything else is given? + return undefined; + }, }); } @@ -306,7 +311,7 @@ function __embind_register_integer(primitiveType, name, minRange, maxRange) { 'toWireType': function(destructors, value) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could // avoid the following two if()s and assume value is of proper type. - if (typeof value !== "number") { + if (typeof value !== "number" && typeof value !== "boolean") { throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); } if (value < minRange || value > maxRange) { @@ -328,8 +333,8 @@ function __embind_register_float(rawType, name) { 'toWireType': function(destructors, value) { // todo: Here we have an opportunity for -O3 level "unsafe" optimizations: we could // avoid the following if() and assume value is of proper type. - if (typeof value !== "number") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' +this.name); + if (typeof value !== "number" && typeof value !== "boolean") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); } return value; }, @@ -449,6 +454,31 @@ function __embind_register_emval(rawType, name) { }); } +function __embind_register_memory_view(rawType, name) { + var typeMapping = [ + Int8Array, + Uint8Array, + Int16Array, + Uint16Array, + Int32Array, + Uint32Array, + Float32Array, + Float64Array, + ]; + + name = readLatin1String(name); + registerType(rawType, { + name: name, + 'fromWireType': function(handle) { + var type = HEAPU32[handle >> 2]; + var size = HEAPU32[(handle >> 2) + 1]; // in elements + var data = HEAPU32[(handle >> 2) + 2]; // byte offset into emscripten heap + var TA = typeMapping[type]; + return new TA(HEAP8.buffer, data, size); + }, + }); +} + function runDestructors(destructors) { while (destructors.length) { var ptr = destructors.pop(); @@ -677,7 +707,7 @@ function __embind_finalize_tuple(rawTupleType) { }, 'toWireType': function(destructors, o) { if (elementsLength !== o.length) { - throw new TypeError("Incorrect number of tuple elements"); + throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length); } var ptr = rawConstructor(); for (var i = 0; i < elementsLength; ++i) { @@ -685,7 +715,7 @@ function __embind_finalize_tuple(rawTupleType) { } if (destructors !== null) { destructors.push(rawDestructor, ptr); - } + } return ptr; }, destructorFunction: rawDestructor, @@ -802,7 +832,9 @@ var genericPointerToWireType = function(destructors, handle) { if (this.isSmartPointer) { var ptr = this.rawConstructor(); - destructors.push(this.rawDestructor, ptr); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } return ptr; } else { return 0; @@ -854,7 +886,9 @@ var genericPointerToWireType = function(destructors, handle) { clonedHandle.delete(); }) ); - destructors.push(this.rawDestructor, ptr); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } } break; @@ -1080,9 +1114,13 @@ ClassHandle.prototype.isAliasOf = function(other) { return leftClass === rightClass && left === right; }; +function throwInstanceAlreadyDeleted(obj) { + throwBindingError(getInstanceTypeName(obj) + ' instance already deleted'); +} + ClassHandle.prototype.clone = function() { if (!this.$$.ptr) { - throwBindingError(getInstanceTypeName(this) + ' instance already deleted'); + throwInstanceAlreadyDeleted(this); } var clone = Object.create(Object.getPrototypeOf(this), { @@ -1104,9 +1142,12 @@ function runDestructor(handle) { } } -ClassHandle.prototype['delete'] = function() { +ClassHandle.prototype['delete'] = function ClassHandle_delete() { if (!this.$$.ptr) { - throwBindingError(getInstanceTypeName(this) + ' instance already deleted'); + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled) { + throwBindingError('Object already scheduled for deletion'); } this.$$.count.value -= 1; @@ -1116,6 +1157,44 @@ ClassHandle.prototype['delete'] = function() { this.$$.smartPtr = undefined; this.$$.ptr = undefined; }; + +var deletionQueue = []; + +ClassHandle.prototype['isDeleted'] = function isDeleted() { + return !this.$$.ptr; +}; + +ClassHandle.prototype['deleteLater'] = function deleteLater() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled) { + throwBindingError('Object already scheduled for deletion'); + } + deletionQueue.push(this); + if (deletionQueue.length === 1 && delayFunction) { + delayFunction(flushPendingDeletes); + } + this.$$.deleteScheduled = true; + return this; +}; + +function flushPendingDeletes() { + while (deletionQueue.length) { + var obj = deletionQueue.pop(); + obj.$$.deleteScheduled = false; + obj['delete'](); + } +} +Module['flushPendingDeletes'] = flushPendingDeletes; + +var delayFunction; +Module['setDelayFunction'] = function setDelayFunction(fn) { + delayFunction = fn; + if (deletionQueue.length && delayFunction) { + delayFunction(flushPendingDeletes); + } +}; function RegisteredClass( name, diff --git a/src/embind/emval.js b/src/embind/emval.js index c02ffa92..77270597 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -1,8 +1,12 @@ -/*global Module*/ +/*global Module:true, Runtime*/ /*global HEAP32*/ +/*global new_*/ +/*global createNamedFunction*/ /*global readLatin1String, writeStringToMemory*/ /*global requireRegisteredType, throwBindingError*/ +var Module = Module || {}; + var _emval_handle_array = [{}]; // reserve zero var _emval_free_list = []; @@ -69,14 +73,8 @@ function __emval_incref(handle) { function __emval_decref(handle) { if (handle && 0 === --_emval_handle_array[handle].refcount) { - delete _emval_handle_array[handle]; + _emval_handle_array[handle] = undefined; _emval_free_list.push(handle); - - var actual_length = _emval_handle_array.length; - while (actual_length > 0 && _emval_handle_array[actual_length - 1] === undefined) { - --actual_length; - } - _emval_handle_array.length = actual_length; } } @@ -108,44 +106,73 @@ function __emval_take_value(type, v) { var __newers = {}; // arity -> function -function __emval_new(handle, argCount, argTypes) { - requireHandle(handle); - var args = parseParameters( - argCount, - argTypes, - Array.prototype.slice.call(arguments, 3)); +function craftEmvalAllocator(argCount) { + /*This function returns a new function that looks like this: + function emval_allocator_3(handle, argTypes, arg0Wired, arg1Wired, arg2Wired) { + var argType0 = requireRegisteredType(HEAP32[(argTypes >> 2)], "parameter 0"); + var arg0 = argType0.fromWireType(arg0Wired); + var argType1 = requireRegisteredType(HEAP32[(argTypes >> 2) + 1], "parameter 1"); + var arg1 = argType1.fromWireType(arg1Wired); + var argType2 = requireRegisteredType(HEAP32[(argTypes >> 2) + 2], "parameter 2"); + var arg2 = argType2.fromWireType(arg2Wired); + var constructor = _emval_handle_array[handle].value; + var emval = new constructor(arg0, arg1, arg2); + return emval; + } */ + + var args1 = ["requireRegisteredType", "HEAP32", "_emval_handle_array", "__emval_register"]; + var args2 = [requireRegisteredType, HEAP32, _emval_handle_array, __emval_register]; + + var argsList = ""; + var argsListWired = ""; + for(var i = 0; i < argCount; ++i) { + argsList += (i!==0?", ":"")+"arg"+i; // 'arg0, arg1, ..., argn' + argsListWired += ", arg"+i+"Wired"; // ', arg0Wired, arg1Wired, ..., argnWired' + } - // Alas, we are forced to use operator new until WebKit enables - // constructing typed arrays without new. - // In WebKit, Uint8Array(10) throws an error. - // In every other browser, it's identical to new Uint8Array(10). + var invokerFnBody = + "return function emval_allocator_"+argCount+"(handle, argTypes " + argsListWired + ") {\n"; + for(var i = 0; i < argCount; ++i) { + invokerFnBody += + "var argType"+i+" = requireRegisteredType(HEAP32[(argTypes >> 2) + "+i+"], \"parameter "+i+"\");\n" + + "var arg"+i+" = argType"+i+".fromWireType(arg"+i+"Wired);\n"; + } + invokerFnBody += + "var constructor = _emval_handle_array[handle].value;\n" + + "var obj = new constructor("+argsList+");\n" + + "return __emval_register(obj);\n" + + "}\n"; + + args1.push(invokerFnBody); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; +} + +function __emval_new(handle, argCount, argTypes) { + requireHandle(handle); + var newer = __newers[argCount]; if (!newer) { - var parameters = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - parameters[i] = 'a' + i; - } - /*jshint evil:true*/ - newer = __newers[argCount] = new Function( - ['c'].concat(parameters), - "return new c(" + parameters.join(',') + ");"); + newer = craftEmvalAllocator(argCount); + __newers[argCount] = newer; } - - var constructor = _emval_handle_array[handle].value; - var obj = newer.apply(undefined, [constructor].concat(args)); -/* - // implement what amounts to operator new - function dummy(){} - dummy.prototype = constructor.prototype; - var obj = new constructor; - var rv = constructor.apply(obj, args); - if (typeof rv === 'object') { - obj = rv; + + if (argCount === 0) { + return newer(handle, argTypes); + } else if (argCount === 1) { + return newer(handle, argTypes, arguments[3]); + } else if (argCount === 2) { + return newer(handle, argTypes, arguments[3], arguments[4]); + } else if (argCount === 3) { + return newer(handle, argTypes, arguments[3], arguments[4], arguments[5]); + } else if (argCount === 4) { + return newer(handle, argTypes, arguments[3], arguments[4], arguments[5], arguments[6]); + } else { + // This is a slow path! (.apply and .splice are slow), so a few specializations are present above. + return newer.apply(null, arguments.splice(1)); } -*/ - return __emval_register(obj); } // appease jshint (technically this code uses eval) @@ -192,38 +219,62 @@ function parseParameters(argCount, argTypes, argWireTypes) { function __emval_call(handle, argCount, argTypes) { requireHandle(handle); + var types = lookupTypes(argCount, argTypes); + + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + args[i] = types[i].fromWireType(arguments[3 + i]); + } + var fn = _emval_handle_array[handle].value; - var args = parseParameters( - argCount, - argTypes, - Array.prototype.slice.call(arguments, 3)); var rv = fn.apply(undefined, args); return __emval_register(rv); } -function __emval_call_method(handle, name, argCount, argTypes) { - requireHandle(handle); - name = getStringOrSymbol(name); - - var args = parseParameters( - argCount, - argTypes, - Array.prototype.slice.call(arguments, 4)); - var obj = _emval_handle_array[handle].value; - var rv = obj[name].apply(obj, args); - return __emval_register(rv); +function lookupTypes(argCount, argTypes, argWireTypes) { + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + a[i] = requireRegisteredType( + HEAP32[(argTypes >> 2) + i], + "parameter " + i); + } + return a; } -function __emval_call_void_method(handle, name, argCount, argTypes) { - requireHandle(handle); - name = getStringOrSymbol(name); +function __emval_get_method_caller(argCount, argTypes) { + var types = lookupTypes(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 args = parseParameters( - argCount, - argTypes, - Array.prototype.slice.call(arguments, 4)); - var obj = _emval_handle_array[handle].value; - obj[name].apply(obj, args); + var argsList = ""; // 'arg0, arg1, arg2, ... , argN' + var argsListWired = ""; // 'arg0Wired, ..., argNWired' + for (var i = 0; i < argCount - 1; ++i) { + argsList += (i !== 0 ? ", " : "") + "arg" + i; + argsListWired += ", arg" + i + "Wired"; + args1.push("argType" + i); + args2.push(types[1 + i]); + } + + var invokerFnBody = + "return Runtime.addFunction(createNamedFunction('" + signatureName + "', function (handle, name" + argsListWired + ") {\n" + + "requireHandle(handle);\n" + + "name = getStringOrSymbol(name);\n"; + + for (var i = 0; i < argCount - 1; ++i) { + invokerFnBody += "var arg" + i + " = argType" + i + ".fromWireType(arg" + i + "Wired);\n"; + } + invokerFnBody += + "var obj = _emval_handle_array[handle].value;\n" + + "return retType.toWireType(null, obj[name](" + argsList + "));\n" + + "}));\n"; + + args1.push(invokerFnBody); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; } function __emval_has_function(handle, name) { diff --git a/src/intertyper.js b/src/intertyper.js index 445c37f4..6da30ae8 100644 --- a/src/intertyper.js +++ b/src/intertyper.js @@ -537,12 +537,17 @@ function intertyper(data, sidePass, baseLineNums) { }); } } else if (!external) { - if (item.tokens[3].text == 'c') - item.tokens.splice(3, 1); - if (item.tokens[3].text in PARSABLE_LLVM_FUNCTIONS) { - ret.value = parseLLVMFunctionCall(item.tokens.slice(2)); + if (item.tokens[3] && item.tokens[3].text != ';') { + if (item.tokens[3].text == 'c') { + item.tokens.splice(3, 1); + } + if (item.tokens[3].text in PARSABLE_LLVM_FUNCTIONS) { + ret.value = parseLLVMFunctionCall(item.tokens.slice(2)); + } else { + ret.value = scanConst(item.tokens[3], ret.type); + } } else { - ret.value = scanConst(item.tokens[3], ret.type); + ret.value = { intertype: 'value', ident: '0', value: '0', type: ret.type }; } } return [ret]; diff --git a/src/jsifier.js b/src/jsifier.js index 3f52337f..156fd65d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -12,6 +12,8 @@ var RELOOP_IGNORED_LASTS = set('return', 'unreachable', 'resume'); var addedLibraryItems = {}; var asmLibraryFunctions = []; +var SETJMP_LABEL = -1; + // JSifier function JSify(data, functionsOnly, givenFunctions) { var mainPass = !functionsOnly; @@ -458,6 +460,7 @@ function JSify(data, functionsOnly, givenFunctions) { } else { ident = '_' + ident; } + if (VERBOSE) printErr('adding ' + ident + ' and deps ' + deps); var depsText = (deps ? '\n' + deps.map(addFromLibrary).filter(function(x) { return x != '' }).join('\n') : ''); var contentText = isFunction ? snippet : ('var ' + ident + '=' + snippet + ';'); if (ASM_JS) { @@ -730,7 +733,7 @@ function JSify(data, functionsOnly, givenFunctions) { }).join('\n') + '\n'; if (func.setjmpTable && ASM_JS) { // emit a label in which we write to the proper local variable, before jumping to the actual label - ret += ' case -1111: '; + ret += ' case ' + SETJMP_LABEL + ': '; ret += func.setjmpTable.map(function(triple) { // original label, label we created for right after the setjmp, variable setjmp result goes into return 'if ((setjmpLabel|0) == ' + getLabelId(triple.oldLabel) + ') { ' + triple.assignTo + ' = threwValue; label = ' + triple.newLabel + ' }\n'; }).join(' else '); @@ -1030,13 +1033,13 @@ function JSify(data, functionsOnly, givenFunctions) { } for (var i = 0; i < idents.length; i++) { if (keys(deps[idents[i]]).length == 0) { - pre = 'var ' + idents[i] + ' = ' + valueJSes[idents[i]] + ';' + pre; + post = 'var ' + idents[i] + ' = ' + valueJSes[idents[i]] + ';' + post; remove(idents[i]); continue mainLoop; } } // If we got here, we have circular dependencies, and must break at least one. - pre = 'var ' + idents[0] + '$phi = ' + valueJSes[idents[0]] + ';' + pre; + pre += 'var ' + idents[0] + '$phi = ' + valueJSes[idents[0]] + ';'; post += 'var ' + idents[0] + ' = ' + idents[0] + '$phi;'; remove(idents[0]); } @@ -1160,6 +1163,7 @@ function JSify(data, functionsOnly, givenFunctions) { return ret + ';'; }); makeFuncLineActor('resume', function(item) { + if (DISABLE_EXCEPTION_CATCHING) return 'abort()'; if (item.ident == 0) { // No exception to resume, so we can just bail. // This is related to issue #917 and http://llvm.org/PR15518 @@ -1181,6 +1185,7 @@ function JSify(data, functionsOnly, givenFunctions) { if (disabled) { ret = call_ + ';'; } else if (ASM_JS) { + call_ = call_.replace('; return', ''); // we auto-add returns when aborting, but do not need them here ret = '(__THREW__ = 0,' + call_ + ');'; } else { ret = '(function() { try { __THREW__ = 0; return ' @@ -1356,7 +1361,7 @@ function JSify(data, functionsOnly, givenFunctions) { var ignoreFunctionIndexizing = []; var useJSArgs = (simpleIdent + '__jsargs') in LibraryManager.library; var hasVarArgs = isVarArgsFunctionType(type); - var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type) : -1; + var normalArgs = (hasVarArgs && !useJSArgs) ? countNormalArgs(type, null, true) : -1; var byPointer = getVarData(funcData, ident); var byPointerForced = false; @@ -1487,9 +1492,9 @@ function JSify(data, functionsOnly, givenFunctions) { } if (ASM_JS && funcData.setjmpTable) { - // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to -111 to handle it. + // check if a longjmp was done. If a setjmp happened, check if ours. If ours, go to a special label to handle it. // otherwise, just return - the call to us must also have been an invoke, so the setjmp propagates that way - ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) > 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = -1111; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; + ret += '; if (((__THREW__|0) != 0) & ((threwValue|0) != 0)) { setjmpLabel = ' + asmCoercion('_testSetjmp(' + makeGetValue('__THREW__', 0, 'i32') + ', setjmpTable)', 'i32') + '; if ((setjmpLabel|0) > 0) { label = ' + SETJMP_LABEL + '; break } else return ' + (funcData.returnType != 'void' ? asmCoercion('0', funcData.returnType) : '') + ' } __THREW__ = threwValue = 0;\n'; } return ret; diff --git a/src/library.js b/src/library.js index 344ec8d6..ab27ed35 100644 --- a/src/library.js +++ b/src/library.js @@ -63,6 +63,36 @@ LibraryManager.library = { // This is set to false when the runtime is initialized, allowing you // to modify the filesystem freely before run() is called. ignorePermissions: true, + createFileHandle: function(stream, fd) { + if (typeof stream === 'undefined') { + stream = null; + } + if (!fd) { + if (stream && stream.socket) { + for (var i = 1; i < 64; i++) { + if (!FS.streams[i]) { + fd = i; + break; + } + } + assert(fd, 'ran out of low fds for sockets'); + } else { + fd = Math.max(FS.streams.length, 64); + for (var i = FS.streams.length; i < fd; i++) { + FS.streams[i] = null; // Keep dense + } + } + } + // Close WebSocket first if we are about to replace the fd (i.e. dup2) + if (FS.streams[fd] && FS.streams[fd].socket && FS.streams[fd].socket.close) { + FS.streams[fd].socket.close(); + } + FS.streams[fd] = stream; + return fd; + }, + removeFileHandle: function(fd) { + FS.streams[fd] = null; + }, joinPath: function(parts, forceRelative) { var ret = parts[0]; for (var i = 1; i < parts.length; i++) { @@ -326,24 +356,25 @@ LibraryManager.library = { #else var chunkSize = 1024*1024; // Chunk size in bytes #endif + if (!hasByteServing) chunkSize = datalength; - + // Function to get a range from the remote URL. var doXHR = (function(from, to) { if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!"); - + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); - + // Some hints to the browser that we want binary data. if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer'; if (xhr.overrideMimeType) { xhr.overrideMimeType('text/plain; charset=x-user-defined'); } - + xhr.send(null); if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status); if (xhr.response !== undefined) { @@ -368,7 +399,7 @@ LibraryManager.library = { this._chunkSize = chunkSize; this.lengthKnown = true; } - + var lazyArray = new LazyUint8Array(); Object.defineProperty(lazyArray, "length", { get: function() { @@ -560,6 +591,7 @@ LibraryManager.library = { var stdout = FS.createDevice(devFolder, 'stdout', null, output); var stderr = FS.createDevice(devFolder, 'stderr', null, error); FS.createDevice(devFolder, 'tty', input, output); + FS.createDevice(devFolder, 'null', function(){}, function(){}); // Create default streams. FS.streams[1] = { @@ -619,7 +651,7 @@ LibraryManager.library = { #endif allocate([ allocate( {{{ Runtime.QUANTUM_SIZE === 4 ? '[0, 0, 0, 0, _stdin, 0, 0, 0, _stdout, 0, 0, 0, _stderr, 0, 0, 0]' : '[0, _stdin, _stdout, _stderr]' }}}, - 'void*', ALLOC_DYNAMIC) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}}); + 'void*', ALLOC_NORMAL) ], 'void*', ALLOC_NONE, {{{ makeGlobalUse('__impure_ptr') }}}); }, quit: function() { @@ -675,10 +707,9 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EACCES); return 0; } - var id = FS.streams.length; // Keep dense var contents = []; for (var key in target.contents) contents.push(key); - FS.streams[id] = { + var id = FS.createFileHandle({ path: path, object: target, // An index into contents. Special values: -2 is ".", -1 is "..". @@ -695,7 +726,7 @@ LibraryManager.library = { contents: contents, // Each stream has its own area for readdir() returns. currentEntry: _malloc(___dirent_struct_layout.__size__) - }; + }); #if ASSERTIONS FS.checkStreams(); #endif @@ -1213,7 +1244,7 @@ LibraryManager.library = { finalPath = path.parentPath + '/' + path.name; } // Actually create an open stream. - var id = FS.streams.length; // Keep dense + var id; if (target.isFolder) { var entryBuffer = 0; if (___dirent_struct_layout) { @@ -1221,7 +1252,7 @@ LibraryManager.library = { } var contents = []; for (var key in target.contents) contents.push(key); - FS.streams[id] = { + id = FS.createFileHandle({ path: finalPath, object: target, // An index into contents. Special values: -2 is ".", -1 is "..". @@ -1238,9 +1269,9 @@ LibraryManager.library = { contents: contents, // Each stream has its own area for readdir() returns. currentEntry: entryBuffer - }; + }); } else { - FS.streams[id] = { + id = FS.createFileHandle({ path: finalPath, object: target, position: 0, @@ -1250,7 +1281,7 @@ LibraryManager.library = { error: false, eof: false, ungotten: [] - }; + }); } #if ASSERTIONS FS.checkStreams(); @@ -1293,10 +1324,7 @@ LibraryManager.library = { newStream[member] = stream[member]; } arg = dup2 ? arg : Math.max(arg, FS.streams.length); // dup2 wants exactly arg; fcntl wants a free descriptor >= arg - for (var i = FS.streams.length; i < arg; i++) { - FS.streams[i] = null; // Keep dense - } - FS.streams[arg] = newStream; + FS.createFileHandle(newStream, arg); #if ASSERTIONS FS.checkStreams(); #endif @@ -1773,12 +1801,14 @@ LibraryManager.library = { return bytesRead; } }, - read__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'pread'], + read__deps: ['$FS', '__setErrNo', '$ERRNO_CODES', 'recv', 'pread'], read: function(fildes, buf, nbyte) { // ssize_t read(int fildes, void *buf, size_t nbyte); // http://pubs.opengroup.org/onlinepubs/000095399/functions/read.html var stream = FS.streams[fildes]; - if (!stream) { + if (stream && ('socket' in stream)) { + return _recv(fildes, buf, nbyte, 0); + } else if (!stream) { ___setErrNo(ERRNO_CODES.EBADF); return -1; } else if (!stream.isRead) { @@ -1804,6 +1834,10 @@ LibraryManager.library = { ___setErrNo(ERRNO_CODES.EIO); return -1; } + if (result === undefined &am |