| // This test times out, probably because of the while loop in the agent. |
| // https://bugs.webkit.org/show_bug.cgi?id=170958 |
| //@ skip |
| |
| const pageSize = 64 * 1024; |
| |
| const verbose = false; |
| |
| // Start multiple agents and create WebAssembly.Memory from each of |
| // them. Perform writes into each memory, and then check that the memory only |
| // contains that agent's writes. This would find bugs where an implementation's |
| // memory reuse is buggy. |
| |
| // Use the agent support from test262: https://github.com/tc39/test262/blob/master/INTERPRETING.md#host-defined-functions |
| |
| const testIterations = 2; |
| const numAgents = 8; |
| const initialPages = 64; |
| const numWrites = 1024; |
| |
| const stateWait = 0; |
| const stateReady = 1; |
| const stateCheck = 2; |
| |
| const startAgents = numAgentsToStart => { |
| for (let a = 0; a < numAgentsToStart; ++a) { |
| const agentScript = ` |
| let state = ${stateWait}; |
| let u8; |
| |
| if (${verbose}) |
| print("Agent ${a} started"); |
| $.agent.report("Agent ${a} started"); |
| |
| $.agent.receiveBroadcast((sab, newState) => { |
| if (${verbose}) |
| print("Agent ${a} received broadcast"); |
| u8 = new Uint8Array(sab); |
| state = newState; |
| }); |
| |
| const busyWaitForValue = value => { |
| // Busy-wait so that once the SAB write occurs all agents try to create a memory at the same time. |
| while (Atomics.load(u8, 0) !== value) ; |
| }; |
| |
| if (${verbose}) |
| print("Agent ${a} waits"); |
| $.agent.report("Agent ${a} waits"); |
| // FIXME: How can this work? The state variable is in the JS heap and the while loop |
| // prevents any JS-heap-modifying things from happening because JS is a synchronous |
| // language |
| // https://bugs.webkit.org/show_bug.cgi?id=170958 |
| while (state === ${stateWait}) ; |
| $.agent.report("Agent ${a} received SAB"); |
| // Use it for faster state change so all agents are more likely to execute at the same time. |
| busyWaitForValue(${stateReady}); |
| |
| let wasmMemory = new WebAssembly.Memory({ initial: ${initialPages} }); |
| let memory = new Uint8Array((wasmMemory).buffer); |
| if (${verbose}) |
| print("Agent ${a} performing writes"); |
| for (let write = 0; write < ${numWrites}; ++write) { |
| // Perform writes of our agent number at a random location. This memory should not be shared, if we see writes of other values then something went wrong. |
| const idx = (Math.random() * ${pageSize} * ${initialPages}) | 0; |
| memory[idx] = ${a}; |
| } |
| if (${verbose}) |
| print("Agent ${a} writes performed"); |
| $.agent.report("Agent ${a} performed writes"); |
| busyWaitForValue(${stateCheck}); |
| |
| if (${verbose}) |
| print("Agent ${a} checking"); |
| // Check that our memory only contains 0 and our agent number. |
| for (let idx = 0; idx < ${pageSize} * ${initialPages}; ++idx) |
| if (memory[idx] !== 0 && memory[idx] !== ${a}) |
| throw new Error("Agent ${a} found unexpected value " + memory[idx] + " at location " + idx); |
| $.agent.report("Agent ${a} checks out OK"); |
| $.agent.leaving(); |
| `; |
| |
| if (verbose) |
| print(`Starting agent ${a}`); |
| $.agent.start(agentScript); |
| } |
| }; |
| |
| const waitForAgents = numAgentsToWaitFor => { |
| for (let a = 0; a < numAgentsToWaitFor; ++a) { |
| while (true) { |
| const report = $.agent.getReport(); |
| if (report === null) { |
| $.agent.sleep(1); |
| continue; |
| } |
| if (verbose) |
| print(`Received: ${report}`); |
| break; |
| } |
| } |
| }; |
| |
| const broadcastToAgents = (sab, newState) => { |
| $.agent.broadcast(sab, newState); |
| }; |
| |
| const sab = new SharedArrayBuffer(1024); |
| const u8 = new Uint8Array(sab); |
| |
| for (let it = 0; it < testIterations; ++it) { |
| startAgents(numAgents); |
| waitForAgents(numAgents); |
| broadcastToAgents(sab, stateReady); |
| waitForAgents(numAgents); |
| $.agent.sleep(1); |
| Atomics.store(u8, 0, stateReady); |
| waitForAgents(numAgents); |
| $.agent.sleep(1); |
| Atomics.store(u8, 0, stateCheck); |
| waitForAgents(numAgents); |
| if (verbose) |
| print("Everyting was fine"); |
| $.agent.sleep(1); |
| } |