// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. $.agent = (function () { var workers = []; var i32a = null; var pendingReports = []; // Agents call Atomics.wait on this location to sleep. var SLEEP_LOC = 0; // 1 if the started worker is ready, 0 otherwise. var START_LOC = 1; // The number of workers that have received the broadcast. var BROADCAST_LOC = 2; // Each worker has a count of outstanding reports; worker N uses memory // location [WORKER_REPORT_LOC + N]. var WORKER_REPORT_LOC = 3; function workerScript(script) { return ` var index; var i32a = null; var broadcasts = []; var pendingReceiver = null; function handleBroadcast() { if (pendingReceiver && broadcasts.length > 0) { pendingReceiver.apply(null, broadcasts.shift()); pendingReceiver = null; } }; var onmessage = function(msg) { switch (msg.kind) { case 'start': i32a = msg.i32a; index = msg.index; (0, eval)(\`${script}\`); break; case 'broadcast': Atomics.add(i32a, ${BROADCAST_LOC}, 1); broadcasts.push([msg.sab, msg.id]); handleBroadcast(); break; } }; var $ = { agent: { receiveBroadcast(receiver) { pendingReceiver = receiver; handleBroadcast(); }, report(msg) { postMessage(msg); Atomics.add(i32a, ${WORKER_REPORT_LOC} + index, 1); }, sleep(s) { Atomics.wait(i32a, ${SLEEP_LOC}, 0, s); }, leaving() {} } };`; } var agent = { start(script) { if (i32a === null) { i32a = new Int32Array(new SharedArrayBuffer(256)); } var w = new Worker(workerScript(script)); w.index = workers.length; w.postMessage({kind: 'start', i32a: i32a, index: w.index}); workers.push(w); }, broadcast(sab, id) { Atomics.store(i32a, BROADCAST_LOC, 0); for (var w of workers) { w.postMessage({kind: 'broadcast', sab: sab, id: id|0}); } while (Atomics.load(i32a, BROADCAST_LOC) != workers.length) {} }, getReport() { for (var w of workers) { while (Atomics.load(i32a, WORKER_REPORT_LOC + w.index) > 0) { pendingReports.push(w.getMessage()); Atomics.sub(i32a, WORKER_REPORT_LOC + w.index, 1); } } return pendingReports.shift() || null; }, sleep(s) { Atomics.wait(i32a, SLEEP_LOC, 0, s); } }; return agent; })();