diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/analyzer.js | 5 | ||||
-rw-r--r-- | src/library.js | 33 | ||||
-rw-r--r-- | src/library_browser.js | 79 | ||||
-rw-r--r-- | src/modules.js | 2 | ||||
-rw-r--r-- | src/postamble.js | 32 | ||||
-rw-r--r-- | src/preamble.js | 6 | ||||
-rw-r--r-- | src/settings.js | 14 | ||||
-rw-r--r-- | src/utility.js | 6 |
8 files changed, 165 insertions, 12 deletions
diff --git a/src/analyzer.js b/src/analyzer.js index 9d060a2c..1849b58d 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -969,7 +969,8 @@ function analyzer(data, sidePass) { // // Analyze our variables and detect their signs. In USE_TYPED_ARRAYS == 2, // we can read signed or unsigned values and prevent the need for signing - // corrections. + // corrections. If on the other hand we are doing corrections anyhow, then + // we can skip this pass. // // For each variable that is the result of a Load, we look a little forward // to see where it is used. We only care about mathops, since only they @@ -978,7 +979,7 @@ function analyzer(data, sidePass) { substrate.addActor('Signalyzer', { processItem: function(item) { this.forwardItem(item, 'QuantumFixer'); - if (USE_TYPED_ARRAYS !== 2) return; + if (USE_TYPED_ARRAYS != 2 || CORRECT_SIGNS == 1) return; function seekIdent(item, obj) { if (item.ident === obj.ident) { diff --git a/src/library.js b/src/library.js index 2855c33d..1164c81f 100644 --- a/src/library.js +++ b/src/library.js @@ -2437,6 +2437,20 @@ LibraryManager.library = { // Supports %x, %4x, %d.%d, %s, %f, %lf. // TODO: Support all format specifiers. format = Pointer_stringify(format); + var soFar = 0; + if (format.indexOf('%n') >= 0) { + // need to track soFar + var _get = get; + get = function() { + soFar++; + return _get(); + } + var _unget = unget; + unget = function() { + soFar--; + return _unget(); + } + } var formatIndex = 0; var argsi = 0; var fields = 0; @@ -2450,6 +2464,7 @@ LibraryManager.library = { } unget(next); next = 1; + mainLoop: for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { if (next <= 0) return fields; var next = get(); @@ -2493,7 +2508,7 @@ LibraryManager.library = { unget(buffer.pop().charCodeAt(0)); } next = get(); - } else { + } else if (type != 'n') { var first = true; while ((curr < max_ || isNaN(max_)) && next > 0) { if (!(next in __scanString.whiteSpace) && // stop on whitespace @@ -2513,7 +2528,7 @@ LibraryManager.library = { first = false; } } - if (buffer.length === 0) return 0; // Failure. + if (buffer.length === 0 && type != 'n') return 0; // Failure. var text = buffer.join(''); var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getNativeFieldSize('void*'); @@ -2541,22 +2556,30 @@ LibraryManager.library = { {{{ makeSetValue('argPtr', 'j', 'array[j]', 'i8') }}} } break; + case 'n': + {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}} + break; } - fields++; + if (type != 'n') fields++; } else if (format[formatIndex] in __scanString.whiteSpace) { while (next in __scanString.whiteSpace) { next = get(); - if (next <= 0) return fields; // End of input. + if (next <= 0) break mainLoop; // End of input. } unget(next); } else { // Not a specifier. if (format[formatIndex].charCodeAt(0) !== next) { unget(next); - return fields; + break mainLoop; } } } + // 'n' is special in that it needs no input. so it can be at the end, even with nothing left to read + if (format[formatIndex-1] == '%' && format[formatIndex] == 'n') { + var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; + {{{ makeSetValue('argPtr', 0, 'soFar-1', 'i32') }}} + } return fields; }, // Performs prtinf-style formatting. diff --git a/src/library_browser.js b/src/library_browser.js index 99106fc3..d7aba76f 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -42,6 +42,7 @@ mergeInto(LibraryManager.library, { }, pointerLock: false, moduleContextCreatedCallbacks: [], + workers: [], ensureObjects: function() { if (Browser.ensured) return; @@ -565,6 +566,84 @@ mergeInto(LibraryManager.library, { } else { return Date.now(); } + }, + + emscripten_create_worker: function(url) { + url = Pointer_stringify(url); + var id = Browser.workers.length; + var info = { + worker: new Worker(url), + callbacks: [], + awaited: 0, + buffer: 0, + bufferSize: 0 + }; + info.worker.onmessage = function(msg) { + var info = Browser.workers[id]; + if (!info) return; // worker was destroyed meanwhile + var callbackId = msg.data['callbackId']; + var callbackInfo = info.callbacks[callbackId]; + if (!callbackInfo) return; // no callback or callback removed meanwhile + info.awaited--; + info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this + var data = msg.data['data']; + if (data) { + if (!data.byteLength) data = new Uint8Array(data); + if (!info.buffer || info.bufferSize < data.length) { + if (info.buffer) _free(info.buffer); + info.bufferSize = data.length; + info.buffer = _malloc(data.length); + } + HEAPU8.set(data, info.buffer); + callbackInfo.func(info.buffer, data.length, callbackInfo.arg); + } else { + callbackInfo.func(0, 0, callbackInfo.arg); + } + }; + Browser.workers.push(info); + return id; + }, + + emscripten_destroy_worker: function(id) { + var info = Browser.workers[id]; + info.worker.terminate(); + if (info.buffer) _free(info.buffer); + Browser.workers[id] = null; + }, + + emscripten_call_worker: function(id, funcName, data, size, callback, arg) { + funcName = Pointer_stringify(funcName); + var info = Browser.workers[id]; + var callbackId = -1; + if (callback) { + callbackId = info.callbacks.length; + info.callbacks.push({ + func: Runtime.getFuncWrapper(callback), + arg: arg + }); + info.awaited++; + } + info.worker.postMessage({ + 'funcName': funcName, + 'callbackId': callbackId, + 'data': data ? {{{ makeHEAPView('U8', 'data', 'data + size') }}} : 0 + }); + }, + + emscripten_worker_respond: function(data, size) { + if (!inWorkerCall) throw 'not in worker call!'; + if (workerResponded) throw 'already responded!'; + workerResponded = true; + postMessage({ + 'callbackId': workerCallbackId, + 'data': data ? {{{ makeHEAPView('U8', 'data', 'data + size') }}} : 0 + }); + }, + + emscripten_get_worker_queue_size: function(id) { + var info = Browser.workers[id]; + if (!info) return -1; + return info.awaited; } }); diff --git a/src/modules.js b/src/modules.js index 7e271e90..ba9f9482 100644 --- a/src/modules.js +++ b/src/modules.js @@ -251,7 +251,7 @@ var Functions = { var indices = vals.toString().replace('"', ''); if (BUILD_AS_SHARED_LIB) { // Shared libraries reuse the parent's function table. - return 'FUNCTION_TABLE = FUNCTION_TABLE.concat([' + indices + ']);'; + return 'FUNCTION_TABLE.push.apply(FUNCTION_TABLE, [' + indices + ']);'; } else { return 'FUNCTION_TABLE = [' + indices + ']; Module["FUNCTION_TABLE"] = FUNCTION_TABLE;'; } diff --git a/src/postamble.js b/src/postamble.js index d164f049..a4c43018 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -113,3 +113,35 @@ if (shouldRunNow) { // {{POST_RUN_ADDITIONS}} +#if BUILD_AS_WORKER + +var buffer = 0, bufferSize = 0; +var inWorkerCall = false, workerResponded = false, workerCallbackId = -1; + +onmessage = function(msg) { + var func = Module['_' + msg.data['funcName']]; + if (!func) throw 'invalid worker function to call: ' + msg.data['funcName']; + var data = msg.data['data']; + if (data) { + if (!data.byteLength) data = new Uint8Array(data); + if (!buffer || bufferSize < data.length) { + if (buffer) _free(buffer); + bufferSize = data.length; + buffer = _malloc(data.length); + } + HEAPU8.set(data, buffer); + } + + inWorkerCall = true; + workerResponded = false; + workerCallbackId = msg.data['callbackId']; + if (data) { + func(buffer, data.length); + } else { + func(0, 0); + } + inWorkerCall = false; +} + +#endif + diff --git a/src/preamble.js b/src/preamble.js index 0fbb6fac..24277014 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -576,9 +576,12 @@ var STACK_ROOT, STACKTOP, STACK_MAX; var STATICTOP; #if USE_TYPED_ARRAYS function enlargeMemory() { +#if ALLOW_MEMORY_GROWTH == 0 + abort('Cannot enlarge memory arrays. Adjust TOTAL_MEMORY or compile with ALLOW_MEMORY_GROWTH'); +#else // TOTAL_MEMORY is the current size of the actual array, and STATICTOP is the new top. #if ASSERTIONS - Module.printErr('Warning: Enlarging memory arrays, this is not fast! ' + [STATICTOP, TOTAL_MEMORY]); + Module.printErr('Warning: Enlarging memory arrays, this is not fast, and ALLOW_MEMORY_GROWTH is not fully tested with all optimizations on! ' + [STATICTOP, TOTAL_MEMORY]); // We perform safe elimination instead of elimination in this mode, but if you see this error, try to disable it and other optimizations entirely assert(STATICTOP >= TOTAL_MEMORY); assert(TOTAL_MEMORY > 4); // So the loop below will not be infinite #endif @@ -609,6 +612,7 @@ function enlargeMemory() { HEAPF64 = new Float64Array(buffer); HEAP8.set(oldHEAP8); #endif +#endif } #endif diff --git a/src/settings.js b/src/settings.js index a6c11448..7e7caa6f 100644 --- a/src/settings.js +++ b/src/settings.js @@ -48,6 +48,13 @@ var TOTAL_MEMORY = 10*1024*1024; // The total amount of memory to use. Using mor // we need to copy the old heap into a new one in that case. var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be // in a flat array. This only matters in non-typed array builds. +var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to allocate more memory than + // we can (TOTAL_MEMORY). If true, we will grow the memory arrays at + // runtime, seamlessly and dynamically. This has a performance cost though, + // both during the actual growth and in general (the latter is because in + // that case we must be careful about optimizations, in particular the + // eliminator). Note that memory growth is only supported with typed + // arrays. // Code embetterments var MICRO_OPTS = 1; // Various micro-optimizations, like nativizing variables @@ -213,10 +220,9 @@ var SHOW_LABELS = 0; // Show labels in the generated code var PRINT_SPLIT_FILE_MARKER = 0; // Prints markers in Javascript generation to split the file later on. See emcc --split option. -var BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library, which - // must be loaded dynamically using dlopen(). +var BUILD_AS_SHARED_LIB = 0; // Whether to build the code as a shared library // 0 here means this is not a shared lib: It is a main file. - // 1 means this is a normal shared lib. + // 1 means this is a normal shared lib, load it with dlopen(). // 2 means this is a shared lib that will be linked at runtime, // which means it will insert its functions into // the global namespace. See STATIC_LIBS_TO_LOAD. @@ -225,6 +231,8 @@ var RUNTIME_LINKED_LIBS = []; // If this is a main file (BUILD_AS_SHARED_LIB == // BUILD_AS_SHARED_LIB == 2. // NOTE: LLVM optimizations run separately on the main file and // linked libraries can break things. +var BUILD_AS_WORKER = 0; // If set to 1, this is a worker library, a special kind of library + // that is run in a worker. See emscripten.h var LINKABLE = 0; // If set to 1, this file can be linked with others, either as a shared // library or as the main file that calls a shared library. To enable that, // we will not internalize all symbols and cull the unused ones, in other diff --git a/src/utility.js b/src/utility.js index 42e8ede4..5019e117 100644 --- a/src/utility.js +++ b/src/utility.js @@ -108,6 +108,12 @@ function zeros(size) { return ret; } +function spaces(size) { + var ret = ''; + for (var i = 0; i < size; i++) ret += ' '; + return ret; +} + function keys(x) { var ret = []; for (var a in x) ret.push(a); |