79a1468831
Changes: - Add possibility to define and emit all reference types. - Simplify function locals definition. - Change 'type' to 'type_index' where appropiate. Bug: v8:7748 Change-Id: Ie35a6204369e678298ee2ff2ec7c7793c5315c3e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2390144 Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/master@{#69814}
216 lines
7.6 KiB
JavaScript
216 lines
7.6 KiB
JavaScript
// Copyright 2018 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.
|
|
|
|
// Flags: --experimental-wasm-threads
|
|
|
|
load("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
const kSequenceLength = 8192;
|
|
const kNumberOfWorkers = 4;
|
|
const kBitMask = kNumberOfWorkers - 1;
|
|
const kMemoryAddress = 0;
|
|
const kSequenceStartAddress = 32;
|
|
|
|
function makeWorkerCodeForOpcode(compareExchangeOpcode, size, functionName,
|
|
builder) {
|
|
let loadMemOpcode = kTrapUnreachable;
|
|
switch (size) {
|
|
case 64:
|
|
loadMemOpcode = kExprI64LoadMem;
|
|
break;
|
|
case 32:
|
|
loadMemOpcode = kExprI64LoadMem32U;
|
|
break;
|
|
case 16:
|
|
loadMemOpcode = kExprI64LoadMem16U;
|
|
break;
|
|
case 8:
|
|
loadMemOpcode = kExprI64LoadMem8U;
|
|
break;
|
|
default:
|
|
throw "!";
|
|
}
|
|
const kArgMemoryCell = 0; // target for atomic ops
|
|
const kArgSequencePtr = 1; // address of sequence
|
|
const kArgSeqenceLength = 2; // lenght of sequence
|
|
const kArgWorkerId = 3; // id of this worker
|
|
const kArgBitMask = 4; // mask to extract worker id from value
|
|
const kLocalCurrentOffset = 5; // current position in sequence in bytes
|
|
const kLocalExpectedValue = 6; // the value we are waiting for
|
|
const kLocalNextValue = 7; // the value to write in the update
|
|
let body = [
|
|
// Turn sequence length to equivalent in bytes.
|
|
kExprLocalGet, kArgSeqenceLength,
|
|
kExprI32Const, size / 8,
|
|
kExprI32Mul,
|
|
kExprLocalSet, kArgSeqenceLength,
|
|
// Outer block so we have something to jump for return.
|
|
...[kExprBlock, kWasmStmt,
|
|
// Set counter to 0.
|
|
kExprI32Const, 0,
|
|
kExprLocalSet, kLocalCurrentOffset,
|
|
// Outer loop until maxcount.
|
|
...[kExprLoop, kWasmStmt,
|
|
// Find the next value to wait for.
|
|
...[kExprLoop, kWasmStmt,
|
|
// Check end of sequence.
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprLocalGet, kArgSeqenceLength,
|
|
kExprI32Eq,
|
|
kExprBrIf, 2, // return
|
|
...[kExprBlock, kWasmStmt,
|
|
// Load next value.
|
|
kExprLocalGet, kArgSequencePtr,
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprI32Add,
|
|
loadMemOpcode, 0, 0,
|
|
// Mask off bits.
|
|
kExprLocalGet, kArgBitMask,
|
|
kExprI64UConvertI32,
|
|
kExprI64And,
|
|
// Compare with worker id.
|
|
kExprLocalGet, kArgWorkerId,
|
|
kExprI64UConvertI32,
|
|
kExprI64Eq,
|
|
kExprBrIf, 0,
|
|
// Not found, increment position.
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprI32Const, size / 8,
|
|
kExprI32Add,
|
|
kExprLocalSet, kLocalCurrentOffset,
|
|
kExprBr, 1,
|
|
kExprEnd
|
|
],
|
|
// Found, end loop.
|
|
kExprEnd
|
|
],
|
|
// Load expected value to local.
|
|
kExprLocalGet, kArgSequencePtr,
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprI32Add,
|
|
loadMemOpcode, 0, 0,
|
|
kExprLocalSet, kLocalExpectedValue,
|
|
// Load value after expected one.
|
|
kExprLocalGet, kArgSequencePtr,
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprI32Add,
|
|
kExprI32Const, size / 8,
|
|
kExprI32Add,
|
|
loadMemOpcode, 0, 0,
|
|
kExprLocalSet, kLocalNextValue,
|
|
// Hammer on memory until value found.
|
|
...[kExprLoop, kWasmStmt,
|
|
// Load address.
|
|
kExprLocalGet, kArgMemoryCell,
|
|
// Load expected value.
|
|
kExprLocalGet, kLocalExpectedValue,
|
|
// Load updated value.
|
|
kExprLocalGet, kLocalNextValue,
|
|
// Try update.
|
|
kAtomicPrefix, compareExchangeOpcode, 0, 0,
|
|
// Load expected value.
|
|
kExprLocalGet, kLocalExpectedValue,
|
|
// Spin if not what expected.
|
|
kExprI64Ne,
|
|
kExprBrIf, 0,
|
|
kExprEnd
|
|
],
|
|
// Next iteration of loop.
|
|
kExprLocalGet, kLocalCurrentOffset,
|
|
kExprI32Const, size / 8,
|
|
kExprI32Add,
|
|
kExprLocalSet, kLocalCurrentOffset,
|
|
kExprBr, 0,
|
|
kExprEnd
|
|
], // outer loop
|
|
kExprEnd
|
|
], // the block
|
|
kExprReturn
|
|
];
|
|
builder.addFunction(functionName, makeSig([kWasmI32, kWasmI32, kWasmI32,
|
|
kWasmI32, kWasmI32
|
|
], []))
|
|
.addLocals(kWasmI32, 1).addLocals(kWasmI64, 2)
|
|
.addBody(body)
|
|
.exportAs(functionName);
|
|
}
|
|
|
|
function generateSequence(typedarray, start, count) {
|
|
let end = count + start;
|
|
for (let i = start; i < end; i++) {
|
|
typedarray[i] = Math.floor(Math.random() * 256);
|
|
}
|
|
}
|
|
|
|
function spawnWorker(module, memory, address, sequence) {
|
|
let workers = [];
|
|
for (let i = 0; i < kNumberOfWorkers; i++) {
|
|
let worker = new Worker(
|
|
`onmessage = function(msg) {
|
|
this.instance = new WebAssembly.Instance(msg.module,
|
|
{m: {imported_mem: msg.memory}});
|
|
instance.exports.worker(msg.address, msg.sequence, msg.sequenceLength, msg.workerId,
|
|
msg.bitMask);
|
|
postMessage({workerId: msg.workerId});
|
|
}`,
|
|
{type: 'string'}
|
|
);
|
|
workers.push(worker);
|
|
worker.postMessage({
|
|
module: module,
|
|
memory: memory,
|
|
address: address,
|
|
sequence: sequence,
|
|
sequenceLength: kSequenceLength,
|
|
workerId: i,
|
|
bitMask: kBitMask
|
|
});
|
|
}
|
|
return workers;
|
|
}
|
|
|
|
function waitForWorkers(workers) {
|
|
for (let worker of workers) {
|
|
worker.getMessage();
|
|
worker.terminate();
|
|
}
|
|
}
|
|
|
|
function testOpcode(opcode, opcodeSize) {
|
|
print("Testing I64AtomicCompareExchange" + opcodeSize);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("m", "imported_mem", 0, 2, "shared");
|
|
|
|
makeWorkerCodeForOpcode(opcode, opcodeSize, "worker", builder);
|
|
|
|
let memory = new WebAssembly.Memory({
|
|
initial: 2,
|
|
maximum: 2,
|
|
shared: true
|
|
});
|
|
let memoryView = new Uint8Array(memory.buffer);
|
|
let numBytes = opcodeSize / 8;
|
|
generateSequence(
|
|
memoryView, kSequenceStartAddress, kSequenceLength * numBytes);
|
|
|
|
// Write the first element of the sequence to memory, such that the workers
|
|
// can start running as soon as they are spawned.
|
|
memoryView.copyWithin(
|
|
kMemoryAddress, kSequenceStartAddress,
|
|
kSequenceStartAddress + numBytes);
|
|
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
let workers =
|
|
spawnWorker(module, memory, kMemoryAddress, kSequenceStartAddress);
|
|
|
|
waitForWorkers(workers);
|
|
|
|
print("DONE");
|
|
}
|
|
|
|
testOpcode(kExprI64AtomicCompareExchange, 64);
|
|
testOpcode(kExprI64AtomicCompareExchange32U, 32);
|
|
testOpcode(kExprI64AtomicCompareExchange16U, 16);
|
|
testOpcode(kExprI64AtomicCompareExchange8U, 8);
|