harness-agent.js 2.79 KB
Newer Older
binji's avatar
binji committed
1 2 3 4
// 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.

littledan's avatar
littledan committed
5
$262.agent = (function () {
binji's avatar
binji committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50

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;
      }
    };

littledan's avatar
littledan committed
51
    var $262 = {
binji's avatar
binji committed
52 53 54 55 56 57 58
      agent: {
        receiveBroadcast(receiver) {
          pendingReceiver = receiver;
          handleBroadcast();
        },

        report(msg) {
59
          postMessage(String(msg));
binji's avatar
binji committed
60 61 62 63 64
          Atomics.add(i32a, ${WORKER_REPORT_LOC} + index, 1);
        },

        sleep(s) { Atomics.wait(i32a, ${SLEEP_LOC}, 0, s); },

65 66 67 68 69
        leaving() {},

        monotonicNow() {
          return performance.now();
        }
binji's avatar
binji committed
70 71 72 73 74 75 76 77 78
      }
    };`;
}

var agent = {
  start(script) {
    if (i32a === null) {
      i32a = new Int32Array(new SharedArrayBuffer(256));
    }
79
    var w = new Worker(workerScript(script), {type: 'string'});
binji's avatar
binji committed
80 81 82 83 84 85
    w.index = workers.length;
    w.postMessage({kind: 'start', i32a: i32a, index: w.index});
    workers.push(w);
  },

  broadcast(sab, id) {
86 87 88 89
    if (!(sab instanceof SharedArrayBuffer)) {
      throw new TypeError('sab must be a SharedArrayBuffer.');
    }

binji's avatar
binji committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    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;
  },

110 111 112 113 114
  sleep(s) { Atomics.wait(i32a, SLEEP_LOC, 0, s); },

  monotonicNow() {
    return performance.now();
  }
binji's avatar
binji committed
115 116 117 118
};
return agent;

})();