aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyzer.js5
-rw-r--r--src/library.js33
-rw-r--r--src/library_browser.js79
-rw-r--r--src/modules.js2
-rw-r--r--src/postamble.js32
-rw-r--r--src/preamble.js6
-rw-r--r--src/settings.js14
-rw-r--r--src/utility.js6
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);