[wasm] Add test for I64AtomicCompareExchange
This adds a stress test for the I64 variants of the AtomicCompareExchange opcodes. Bug: v8:6532 Change-Id: Iaba4f31f944a71393e5c3222d364d214ff482b9e Reviewed-on: https://chromium-review.googlesource.com/1235913 Commit-Queue: Stephan Herhut <herhut@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#56261}
This commit is contained in:
parent
bcbb6d9eb4
commit
94364486c6
@ -133,10 +133,10 @@ function makeWorkerCodeForOpcode(compareExchangeOpcode, size, functionName,
|
||||
.exportAs(functionName);
|
||||
}
|
||||
|
||||
function generateSequence(typedarray, start, count, size) {
|
||||
function generateSequence(typedarray, start, count) {
|
||||
let end = count + start;
|
||||
for (let i = start; i < end; i++) {
|
||||
typedarray[i] = Math.floor(Math.random() * (1 << (size - 1)) * 2);
|
||||
typedarray[i] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,8 +174,7 @@ function waitForWorkers(workers) {
|
||||
}
|
||||
}
|
||||
|
||||
function testOpcode(opcode, ta_constructor) {
|
||||
let opcodeSize = 8 * ta_constructor.BYTES_PER_ELEMENT;
|
||||
function testOpcode(opcode, opcodeSize) {
|
||||
print("Testing I32AtomicCompareExchange" + opcodeSize);
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addImportedMemory("m", "imported_mem", 0, 1, "shared");
|
||||
@ -187,22 +186,22 @@ function testOpcode(opcode, ta_constructor) {
|
||||
maximum: 1,
|
||||
shared: true
|
||||
});
|
||||
let memoryView = new ta_constructor(memory.buffer);
|
||||
let sequenceStartInView = kSequenceStartAddress / ta_constructor.BYTES_PER_ELEMENT;
|
||||
generateSequence(memoryView, sequenceStartInView, kSequenceLength,
|
||||
opcodeSize);
|
||||
let memoryView = new Uint8Array(memory.buffer);
|
||||
generateSequence(memoryView, kSequenceStartAddress, kSequenceLength * (opcodeSize / 8));
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let workers = spawnWorker(module, memory, 0, kSequenceStartAddress);
|
||||
|
||||
// Fire the workers off
|
||||
memoryView[0] = memoryView[sequenceStartInView];
|
||||
for (let i = opcodeSize / 8 - 1; i >= 0; i--) {
|
||||
memoryView[i] = memoryView[kSequenceStartAddress + i];
|
||||
}
|
||||
|
||||
waitForWorkers(workers);
|
||||
|
||||
print("DONE");
|
||||
}
|
||||
|
||||
testOpcode(kExprI32AtomicCompareExchange, Int32Array);
|
||||
testOpcode(kExprI32AtomicCompareExchange16U, Int16Array);
|
||||
testOpcode(kExprI32AtomicCompareExchange8U, Int8Array);
|
||||
testOpcode(kExprI32AtomicCompareExchange, 32);
|
||||
testOpcode(kExprI32AtomicCompareExchange16U, 16);
|
||||
testOpcode(kExprI32AtomicCompareExchange8U, 8);
|
||||
|
213
test/mjsunit/wasm/compare-exchange64-stress.js
Normal file
213
test/mjsunit/wasm/compare-exchange64-stress.js
Normal file
@ -0,0 +1,213 @@
|
||||
// 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-constants.js");
|
||||
load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
const kSequenceLength = 8192;
|
||||
const kNumberOfWorkers = 4;
|
||||
const kBitMask = kNumberOfWorkers - 1;
|
||||
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.
|
||||
kExprGetLocal, kArgSeqenceLength,
|
||||
kExprI32Const, size / 8,
|
||||
kExprI32Mul,
|
||||
kExprSetLocal, kArgSeqenceLength,
|
||||
// Outer block so we have something to jump for return.
|
||||
...[kExprBlock, kWasmStmt,
|
||||
// Set counter to 0.
|
||||
kExprI32Const, 0,
|
||||
kExprSetLocal, kLocalCurrentOffset,
|
||||
// Outer loop until maxcount.
|
||||
...[kExprLoop, kWasmStmt,
|
||||
// Find the next value to wait for.
|
||||
...[kExprLoop, kWasmStmt,
|
||||
// Check end of sequence.
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprGetLocal, kArgSeqenceLength,
|
||||
kExprI32Eq,
|
||||
kExprBrIf, 2, // return
|
||||
...[kExprBlock, kWasmStmt,
|
||||
// Load next value.
|
||||
kExprGetLocal, kArgSequencePtr,
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprI32Add,
|
||||
loadMemOpcode, 0, 0,
|
||||
// Mask off bits.
|
||||
kExprGetLocal, kArgBitMask,
|
||||
kExprI64UConvertI32,
|
||||
kExprI64And,
|
||||
// Compare with worker id.
|
||||
kExprGetLocal, kArgWorkerId,
|
||||
kExprI64UConvertI32,
|
||||
kExprI64Eq,
|
||||
kExprBrIf, 0,
|
||||
// Not found, increment position.
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprI32Const, size / 8,
|
||||
kExprI32Add,
|
||||
kExprSetLocal, kLocalCurrentOffset,
|
||||
kExprBr, 1,
|
||||
kExprEnd
|
||||
],
|
||||
// Found, end loop.
|
||||
kExprEnd
|
||||
],
|
||||
// Load expected value to local.
|
||||
kExprGetLocal, kArgSequencePtr,
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprI32Add,
|
||||
loadMemOpcode, 0, 0,
|
||||
kExprSetLocal, kLocalExpectedValue,
|
||||
// Load value after expected one.
|
||||
kExprGetLocal, kArgSequencePtr,
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprI32Add,
|
||||
kExprI32Const, size / 8,
|
||||
kExprI32Add,
|
||||
loadMemOpcode, 0, 0,
|
||||
kExprSetLocal, kLocalNextValue,
|
||||
// Hammer on memory until value found.
|
||||
...[kExprLoop, kWasmStmt,
|
||||
// Load address.
|
||||
kExprGetLocal, kArgMemoryCell,
|
||||
// Load expected value.
|
||||
kExprGetLocal, kLocalExpectedValue,
|
||||
// Load updated value.
|
||||
kExprGetLocal, kLocalNextValue,
|
||||
// Try update.
|
||||
kAtomicPrefix, compareExchangeOpcode, 0, 0,
|
||||
// Load expected value.
|
||||
kExprGetLocal, kLocalExpectedValue,
|
||||
// Spin if not what expected.
|
||||
kExprI64Ne,
|
||||
kExprBrIf, 0,
|
||||
kExprEnd
|
||||
],
|
||||
// Next iteration of loop.
|
||||
kExprGetLocal, kLocalCurrentOffset,
|
||||
kExprI32Const, size / 8,
|
||||
kExprI32Add,
|
||||
kExprSetLocal, kLocalCurrentOffset,
|
||||
kExprBr, 0,
|
||||
kExprEnd
|
||||
], // outer loop
|
||||
kExprEnd
|
||||
], // the block
|
||||
kExprReturn
|
||||
];
|
||||
builder.addFunction(functionName, makeSig([kWasmI32, kWasmI32, kWasmI32,
|
||||
kWasmI32, kWasmI32
|
||||
], []))
|
||||
.addLocals({
|
||||
i32_count: 1, i64_count: 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);
|
||||
generateSequence(memoryView, kSequenceStartAddress, kSequenceLength * (opcodeSize / 8));
|
||||
|
||||
let module = new WebAssembly.Module(builder.toBuffer());
|
||||
let workers = spawnWorker(module, memory, 0, kSequenceStartAddress);
|
||||
|
||||
// Fire the workers off
|
||||
for (let i = opcodeSize / 8 - 1; i >= 0; i--) {
|
||||
memoryView[i] = memoryView[kSequenceStartAddress + i];
|
||||
}
|
||||
|
||||
waitForWorkers(workers);
|
||||
|
||||
print("DONE");
|
||||
}
|
||||
|
||||
testOpcode(kExprI64AtomicCompareExchange, 64);
|
||||
testOpcode(kExprI64AtomicCompareExchange32U, 32);
|
||||
testOpcode(kExprI64AtomicCompareExchange16U, 16);
|
||||
testOpcode(kExprI64AtomicCompareExchange8U, 8);
|
@ -371,6 +371,39 @@ let kExprI32AtomicExchange16U = 0x44;
|
||||
let kExprI32AtomicCompareExchange = 0x48
|
||||
let kExprI32AtomicCompareExchange8U = 0x4a
|
||||
let kExprI32AtomicCompareExchange16U = 0x4b
|
||||
|
||||
let kExprI64AtomicLoad = 0x11;
|
||||
let kExprI64AtomicLoad8U = 0x14;
|
||||
let kExprI64AtomicLoad16U = 0x15;
|
||||
let kExprI64AtomicLoad32U = 0x16;
|
||||
let kExprI64AtomicStore = 0x18;
|
||||
let kExprI64AtomicStore8U = 0x1b;
|
||||
let kExprI64AtomicStore16U = 0x1c;
|
||||
let kExprI64AtomicStore32U = 0x1d;
|
||||
let kExprI64AtomicAdd = 0x1f;
|
||||
let kExprI64AtomicAdd8U = 0x22;
|
||||
let kExprI64AtomicAdd16U = 0x23;
|
||||
let kExprI64AtomicAdd32U = 0x24;
|
||||
let kExprI64AtomicSub = 0x26;
|
||||
let kExprI64AtomicSub8U = 0x29;
|
||||
let kExprI64AtomicSub16U = 0x2a;
|
||||
let kExprI64AtomicSub32U = 0x2b;
|
||||
let kExprI64AtomicAnd = 0x2d;
|
||||
let kExprI64AtomicAnd8U = 0x30;
|
||||
let kExprI64AtomicAnd16U = 0x31;
|
||||
let kExprI64AtomicAnd32U = 0x32;
|
||||
let kExprI64AtomicOr = 0x34;
|
||||
let kExprI64AtomicOr8U = 0x37;
|
||||
let kExprI64AtomicOr16U = 0x38;
|
||||
let kExprI64AtomicOr32U = 0x39;
|
||||
let kExprI64AtomicXor = 0x3b;
|
||||
let kExprI64AtomicXor8U = 0x3e;
|
||||
let kExprI64AtomicXor16U = 0x3f;
|
||||
let kExprI64AtomicXor32U = 0x40;
|
||||
let kExprI64AtomicExchange = 0x42;
|
||||
let kExprI64AtomicExchange8U = 0x45;
|
||||
let kExprI64AtomicExchange16U = 0x46;
|
||||
let kExprI64AtomicExchange32U = 0x47;
|
||||
let kExprI64AtomicCompareExchange = 0x49
|
||||
let kExprI64AtomicCompareExchange8U = 0x4c;
|
||||
let kExprI64AtomicCompareExchange16U = 0x4d;
|
||||
|
Loading…
Reference in New Issue
Block a user