diff --git a/test/mjsunit/wasm/compare-exchange-stress.js b/test/mjsunit/wasm/compare-exchange-stress.js index ac48388a42..d308919088 100644 --- a/test/mjsunit/wasm/compare-exchange-stress.js +++ b/test/mjsunit/wasm/compare-exchange-stress.js @@ -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); diff --git a/test/mjsunit/wasm/compare-exchange64-stress.js b/test/mjsunit/wasm/compare-exchange64-stress.js new file mode 100644 index 0000000000..89cc7ecb34 --- /dev/null +++ b/test/mjsunit/wasm/compare-exchange64-stress.js @@ -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); diff --git a/test/mjsunit/wasm/wasm-constants.js b/test/mjsunit/wasm/wasm-constants.js index 57b746b8f7..cc10e9953c 100644 --- a/test/mjsunit/wasm/wasm-constants.js +++ b/test/mjsunit/wasm/wasm-constants.js @@ -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;