Commit 14bfcf7c authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[mjsunit/wasm] Reuse WebAssembly.Memory objects in stress test

In the atomics stress, the search for sequential sequences creates
lots of new WebAssembly.Memory objects. This memory pressure is not
central to this test, so reuse the same memory to make them less
flaky.

R=mstarzinger@chromium.org

Change-Id: I8d135e7b82d572cb1df38f37a4e2f6393f6b2e05
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1697247Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62644}
parent 98bc64d3
......@@ -9,7 +9,7 @@
// Note that results of this test are flaky by design. While the test is
// deterministic with a fixed seed, bugs may introduce non-determinism.
load("test/mjsunit/wasm/wasm-module-builder.js");
load('test/mjsunit/wasm/wasm-module-builder.js');
const kDebug = false;
......@@ -22,67 +22,47 @@ const kFirstOpcodeWithoutOutput = 3;
const kLastOpcodeWithoutOutput = 5;
const opCodes = [
kExprI32AtomicLoad,
kExprI32AtomicLoad8U,
kExprI32AtomicLoad16U,
kExprI32AtomicStore,
kExprI32AtomicStore8U,
kExprI32AtomicStore16U,
kExprI32AtomicAdd,
kExprI32AtomicAdd8U,
kExprI32AtomicAdd16U,
kExprI32AtomicSub,
kExprI32AtomicSub8U,
kExprI32AtomicSub16U,
kExprI32AtomicAnd,
kExprI32AtomicAnd8U,
kExprI32AtomicAnd16U,
kExprI32AtomicOr,
kExprI32AtomicOr8U,
kExprI32AtomicOr16U,
kExprI32AtomicXor,
kExprI32AtomicXor8U,
kExprI32AtomicXor16U,
kExprI32AtomicExchange,
kExprI32AtomicExchange8U,
kExprI32AtomicExchange16U
kExprI32AtomicLoad, kExprI32AtomicLoad8U, kExprI32AtomicLoad16U,
kExprI32AtomicStore, kExprI32AtomicStore8U, kExprI32AtomicStore16U,
kExprI32AtomicAdd, kExprI32AtomicAdd8U, kExprI32AtomicAdd16U,
kExprI32AtomicSub, kExprI32AtomicSub8U, kExprI32AtomicSub16U,
kExprI32AtomicAnd, kExprI32AtomicAnd8U, kExprI32AtomicAnd16U,
kExprI32AtomicOr, kExprI32AtomicOr8U, kExprI32AtomicOr16U,
kExprI32AtomicXor, kExprI32AtomicXor8U, kExprI32AtomicXor16U,
kExprI32AtomicExchange, kExprI32AtomicExchange8U, kExprI32AtomicExchange16U
];
const opCodeNames = [
"kExprI32AtomicLoad",
"kExprI32AtomicLoad8U",
"kExprI32AtomicLoad16U",
"kExprI32AtomicStore",
"kExprI32AtomicStore8U",
"kExprI32AtomicStore16U",
"kExprI32AtomicAdd",
"kExprI32AtomicAdd8U",
"kExprI32AtomicAdd16U",
"kExprI32AtomicSub",
"kExprI32AtomicSub8U",
"kExprI32AtomicSub16U",
"kExprI32AtomicAnd",
"kExprI32AtomicAnd8U",
"kExprI32AtomicAnd16U",
"kExprI32AtomicOr",
"kExprI32AtomicOr8U",
"kExprI32AtomicOr16U",
"kExprI32AtomicXor",
"kExprI32AtomicXor8U",
"kExprI32AtomicXor16U",
"kExprI32AtomicExchange",
"kExprI32AtomicExchange8U",
"kExprI32AtomicExchange16U"
'kExprI32AtomicLoad', 'kExprI32AtomicLoad8U',
'kExprI32AtomicLoad16U', 'kExprI32AtomicStore',
'kExprI32AtomicStore8U', 'kExprI32AtomicStore16U',
'kExprI32AtomicAdd', 'kExprI32AtomicAdd8U',
'kExprI32AtomicAdd16U', 'kExprI32AtomicSub',
'kExprI32AtomicSub8U', 'kExprI32AtomicSub16U',
'kExprI32AtomicAnd', 'kExprI32AtomicAnd8U',
'kExprI32AtomicAnd16U', 'kExprI32AtomicOr',
'kExprI32AtomicOr8U', 'kExprI32AtomicOr16U',
'kExprI32AtomicXor', 'kExprI32AtomicXor8U',
'kExprI32AtomicXor16U', 'kExprI32AtomicExchange',
'kExprI32AtomicExchange8U', 'kExprI32AtomicExchange16U'
];
let kMaxMemPages = 10;
let gSharedMemory =
new WebAssembly.Memory({initial: 1, maximum: kMaxMemPages, shared: true});
let gSharedMemoryView = new Int32Array(gSharedMemory.buffer);
let gPrivateMemory =
new WebAssembly.Memory({initial: 1, maximum: kMaxMemPages, shared: true});
let gPrivateMemoryView = new Int32Array(gPrivateMemory.buffer);
class Operation {
constructor(opcode, input, offset) {
this.opcode = opcode != undefined ? opcode : Operation.nextOpcode();
this.size = Operation.opcodeToSize(this.opcode);
this.input = input != undefined ? input : Operation.inputForSize(
this.size);
this.offset = offset != undefined ? offset : Operation.offsetForSize(
this.size);
this.input = input != undefined ? input : Operation.inputForSize(this.size);
this.offset =
offset != undefined ? offset : Operation.offsetForSize(this.size);
}
static nextOpcode() {
......@@ -109,7 +89,8 @@ class Operation {
static offsetForSize(size) {
// Pick an offset in bytes between 0 and 7.
let offset = Math.floor(Math.random() * 8);
// Make sure the offset matches the required alignment by masking out the lower bits.
// Make sure the offset matches the required alignment by masking out the
// lower bits.
let size_in_bytes = size / 8;
let mask = ~(size_in_bytes - 1);
return offset & mask;
......@@ -117,7 +98,10 @@ class Operation {
get wasmOpcode() {
// [opcode, alignment, offset]
return [opCodes[this.opcode], Operation.opcodeToAlignment(this.opcode), this.offset];
return [
opCodes[this.opcode], Operation.opcodeToAlignment(this.opcode),
this.offset
];
}
get hasInput() {
......@@ -125,18 +109,20 @@ class Operation {
}
get hasOutput() {
return this.opcode < kFirstOpcodeWithoutOutput || this.opcode >
kLastOpcodeWithoutOutput;
return this.opcode < kFirstOpcodeWithoutOutput ||
this.opcode > kLastOpcodeWithoutOutput;
}
truncateResultBits(low, high) {
// Shift the lower part. For offsets greater four it drops out of the visible window.
// Shift the lower part. For offsets greater four it drops out of the
// visible window.
let shiftedL = this.offset >= 4 ? 0 : low >>> (this.offset * 8);
// The higher part is zero for offset 0, left shifted for [1..3] and right shifted
// for [4..7].
let shiftedH = this.offset == 0 ? 0 :
this.offset >= 4 ? high >>> (this.offset - 4) * 8 : high << ((4 -
this.offset) * 8);
// The higher part is zero for offset 0, left shifted for [1..3] and right
// shifted for [4..7].
let shiftedH = this.offset == 0 ?
0 :
this.offset >= 4 ? high >>> (this.offset - 4) * 8 :
high << ((4 - this.offset) * 8);
let value = shiftedL | shiftedH;
switch (this.size) {
......@@ -147,15 +133,14 @@ class Operation {
case 32:
return value;
default:
throw "Unexpected size: " + this.size;
throw 'Unexpected size: ' + this.size;
}
}
static get builder() {
if (!Operation.__builder) {
let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, 1, false);
builder.exportMemoryAs("mem");
builder.addImportedMemory('m', 'imported_mem', 0, kMaxMemPages, 'shared');
Operation.__builder = builder;
}
return Operation.__builder;
......@@ -168,10 +153,6 @@ class Operation {
return Operation.__instance.exports;
}
static get memory() {
return Operation.exports.mem;
}
static set instance(instance) {
Operation.__instance = instance;
}
......@@ -184,13 +165,11 @@ class Operation {
// Load address of low 32 bits.
kExprI32Const, 0,
// Load expected value.
kExprGetLocal, 0,
kExprI32StoreMem, 2, 0,
kExprGetLocal, 0, kExprI32StoreMem, 2, 0,
// Load address of high 32 bits.
kExprI32Const, 4,
// Load expected value.
kExprGetLocal, 1,
kExprI32StoreMem, 2, 0,
kExprGetLocal, 1, kExprI32StoreMem, 2, 0,
// Load address of where our window starts.
kExprI32Const, 0,
// Load input if there is one.
......@@ -200,8 +179,7 @@ class Operation {
// Drop output if it had any.
...(this.hasOutput ? [kExprDrop] : []),
// Load resulting value.
kExprI32Const, 0,
kExprI32LoadMem, 2, 0,
kExprI32Const, 0, kExprI32LoadMem, 2, 0,
// Return.
kExprReturn
]
......@@ -210,28 +188,27 @@ class Operation {
.exportAs(this.key);
// Instantiate module, get function exports.
let module = new WebAssembly.Module(builder.toBuffer());
Operation.instance = new WebAssembly.Instance(module);
Operation.instance =
new WebAssembly.Instance(module, {m: {imported_mem: gPrivateMemory}});
evalFun = Operation.exports[this.key];
}
let result = evalFun(state.low, state.high, this.input);
let ta = new Int32Array(Operation.memory.buffer);
let ta = gPrivateMemoryView;
if (kDebug) {
print(state.high + ":" + state.low + " " + this.toString() +
" -> " + ta[1] + ":" + ta[0]);
print(
state.high + ':' + state.low + ' ' + this.toString() + ' -> ' +
ta[1] + ':' + ta[0]);
}
if (result != ta[0]) throw "!";
return {
low: ta[0],
high: ta[1]
};
if (result != ta[0]) throw '!';
return {low: ta[0], high: ta[1]};
}
toString() {
return opCodeNames[this.opcode] + "[+" + this.offset + "] " + this.input;
return opCodeNames[this.opcode] + '[+' + this.offset + '] ' + this.input;
}
get key() {
return this.opcode + "-" + this.offset;
return this.opcode + '-' + this.offset;
}
}
......@@ -248,7 +225,7 @@ class State {
}
toString() {
return this.high + ":" + this.low + " @ " + this.indices;
return this.high + ':' + this.low + ' @ ' + this.indices;
}
}
......@@ -284,18 +261,12 @@ function generateFunctionBodyForSequence(sequence) {
if (!kDebug) {
body.push(
// Decrement the wait count.
kExprGetLocal, 2,
kExprI32Const, 1,
kAtomicPrefix, kExprI32AtomicSub, 2, 0,
kExprGetLocal, 2, kExprI32Const, 1, kAtomicPrefix, kExprI32AtomicSub, 2,
0,
// Spin until zero.
kExprLoop, kWasmStmt,
kExprGetLocal, 2,
kAtomicPrefix, kExprI32AtomicLoad, 2, 0,
kExprI32Const, 0,
kExprI32GtU,
kExprBrIf, 0,
kExprEnd
);
kExprLoop, kWasmStmt, kExprGetLocal, 2, kAtomicPrefix,
kExprI32AtomicLoad, 2, 0, kExprI32Const, 0, kExprI32GtU, kExprBrIf, 0,
kExprEnd);
}
for (let operation of sequence) {
body.push(
......@@ -304,8 +275,9 @@ function generateFunctionBodyForSequence(sequence) {
// Load address where atomic pointers are stored.
kExprGetLocal, 0,
// Load the second argument if it had any.
...(operation.hasInput ? [kExprI32Const, ...toSLeb128(operation
.input)] : []),
...(operation.hasInput ?
[kExprI32Const, ...toSLeb128(operation.input)] :
[]),
// Perform operation
kAtomicPrefix, ...operation.wasmOpcode,
// Generate fake output in needed.
......@@ -313,21 +285,17 @@ function generateFunctionBodyForSequence(sequence) {
// Store read intermediate to sequence.
kExprI32StoreMem, 2, 0,
// Increment result sequence pointer.
kExprGetLocal, 1,
kExprI32Const, 4,
kExprI32Add,
kExprSetLocal, 1
);
kExprGetLocal, 1, kExprI32Const, 4, kExprI32Add, kExprSetLocal, 1);
}
// Return end of sequence index.
body.push(
kExprGetLocal, 1,
kExprReturn);
body.push(kExprGetLocal, 1, kExprReturn);
return body;
}
function getSequence(start, end) {
return new Int32Array(memory.buffer, start, (end - start) / Int32Array.BYTES_PER_ELEMENT);
return new Int32Array(
gSharedMemory.buffer, start,
(end - start) / Int32Array.BYTES_PER_ELEMENT);
}
function spawnWorkers() {
......@@ -348,8 +316,8 @@ function spawnWorkers() {
let result = instance.exports["worker" + index](address, sequence, spin);
postMessage({index: index, sequence: sequence, result: result});
}
}`, {type: 'string'}
);
}`,
{type: 'string'});
workers.push(worker);
}
return workers;
......@@ -357,12 +325,9 @@ function spawnWorkers() {
function instantiateModuleInWorkers(workers) {
for (let worker of workers) {
worker.postMessage({
module: module,
mem: memory
});
worker.postMessage({module: module, mem: gSharedMemory});
let msg = worker.getMessage();
if (!msg.instantiated) throw "Worker failed to instantiate";
if (!msg.instantiated) throw 'Worker failed to instantiate';
}
}
......@@ -391,7 +356,8 @@ function selectMatchingWorkers(state) {
if (index >= kSequenceLength) continue;
// We need to project the expected value to the number of bits this
// operation will read at runtime.
let expected = sequences[i][index].truncateResultBits(state.low, state.high);
let expected =
sequences[i][index].truncateResultBits(state.low, state.high);
let hasOutput = sequences[i][index].hasOutput;
if (!hasOutput || (results[i][index] == expected)) {
matching.push(i);
......@@ -405,10 +371,7 @@ function computeNextState(state, advanceIdx) {
let sequence = sequences[advanceIdx];
let operation = sequence[state.indices[advanceIdx]];
newIndices[advanceIdx]++;
let {
low,
high
} = operation.compute(state);
let {low, high} = operation.compute(state);
return new State(low, high, newIndices, state.count + 1);
}
......@@ -434,7 +397,7 @@ function findSequentialOrdering() {
matchingStates.push(newState);
}
if (steps++ > kNumberOfSteps) {
print("Search timed out, aborting...");
print('Search timed out, aborting...');
return true;
}
}
......@@ -451,12 +414,12 @@ function loadSequencesFromStrings(inputs) {
let sequences = [];
let parseRE = /([a-zA-Z0-9]*)\[\+([0-9])\] ([\-0-9]*)/;
for (let input of inputs) {
let parts = input.split(",");
let parts = input.split(',');
let sequence = [];
for (let part of parts) {
let parsed = parseRE.exec(part);
sequence.push(new Operation(reverseOpcodes[parsed[1]], parsed[3],
parsed[2] | 0));
sequence.push(
new Operation(reverseOpcodes[parsed[1]], parsed[3], parsed[2] | 0));
}
sequences.push(sequence);
}
......@@ -467,7 +430,7 @@ function loadSequencesFromStrings(inputs) {
function loadResultsFromStrings(inputs) {
let results = [];
for (let input of inputs) {
let parts = input.split(",");
let parts = input.split(',');
let result = [];
for (let number of parts) {
result.push(number | 0);
......@@ -477,39 +440,28 @@ function loadResultsFromStrings(inputs) {
return results;
}
let maxSize = 10;
let memory = new WebAssembly.Memory({
initial: 1,
maximum: maxSize,
shared: true
});
let memory_view = new Int32Array(memory.buffer);
let sequences = [];
let results = [];
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem", 0, maxSize, "shared");
builder.addImportedMemory('m', 'imported_mem', 0, kMaxMemPages, 'shared');
for (let i = 0; i < kNumberOfWorker; i++) {
sequences[i] = makeSequenceOfOperations(kSequenceLength);
builder.addFunction("worker" + i, kSig_i_iii)
builder.addFunction('worker' + i, kSig_i_iii)
.addBody(generateFunctionBodyForSequence(sequences[i]))
.exportAs("worker" + i);
.exportAs('worker' + i);
}
// Instantiate module, get function exports.
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module, {
m: {
imported_mem: memory
}
});
let instance =
new WebAssembly.Instance(module, {m: {imported_mem: gSharedMemory}});
// Spawn off the workers and run the sequences.
let workers = spawnWorkers();
// Set spin count.
memory_view[4] = kNumberOfWorker;
gSharedMemoryView[4] = kNumberOfWorker;
instantiateModuleInWorkers(workers);
executeSequenceInWorkers(workers);
......@@ -541,13 +493,13 @@ if (kDebug) {
let passed = findSequentialOrdering();
if (passed) {
print("PASS");
print('PASS');
} else {
for (let i = 0; i < kNumberOfWorker; i++) {
print("Worker " + i);
print('Worker ' + i);
print(sequences[i]);
print(results[i]);
}
print("FAIL");
print('FAIL');
quit(-1);
}
......@@ -9,7 +9,7 @@
// Note that results of this test are flaky by design. While the test is
// deterministic with a fixed seed, bugs may introduce non-determinism.
load("test/mjsunit/wasm/wasm-module-builder.js");
load('test/mjsunit/wasm/wasm-module-builder.js');
const kDebug = false;
......@@ -22,75 +22,47 @@ const kFirstOpcodeWithoutOutput = 4;
const kLastOpcodeWithoutOutput = 7;
const opCodes = [
kExprI64AtomicLoad,
kExprI64AtomicLoad8U,
kExprI64AtomicLoad16U,
kExprI64AtomicLoad32U,
kExprI64AtomicStore,
kExprI64AtomicStore8U,
kExprI64AtomicStore16U,
kExprI64AtomicStore32U,
kExprI64AtomicAdd,
kExprI64AtomicAdd8U,
kExprI64AtomicAdd16U,
kExprI64AtomicAdd32U,
kExprI64AtomicSub,
kExprI64AtomicSub8U,
kExprI64AtomicSub16U,
kExprI64AtomicSub32U,
kExprI64AtomicAnd,
kExprI64AtomicAnd8U,
kExprI64AtomicAnd16U,
kExprI64AtomicAnd32U,
kExprI64AtomicOr,
kExprI64AtomicOr8U,
kExprI64AtomicOr16U,
kExprI64AtomicOr32U,
kExprI64AtomicXor,
kExprI64AtomicXor8U,
kExprI64AtomicXor16U,
kExprI64AtomicXor32U,
kExprI64AtomicExchange,
kExprI64AtomicExchange8U,
kExprI64AtomicExchange16U,
kExprI64AtomicExchange32U
kExprI64AtomicLoad, kExprI64AtomicLoad8U, kExprI64AtomicLoad16U,
kExprI64AtomicLoad32U, kExprI64AtomicStore, kExprI64AtomicStore8U,
kExprI64AtomicStore16U, kExprI64AtomicStore32U, kExprI64AtomicAdd,
kExprI64AtomicAdd8U, kExprI64AtomicAdd16U, kExprI64AtomicAdd32U,
kExprI64AtomicSub, kExprI64AtomicSub8U, kExprI64AtomicSub16U,
kExprI64AtomicSub32U, kExprI64AtomicAnd, kExprI64AtomicAnd8U,
kExprI64AtomicAnd16U, kExprI64AtomicAnd32U, kExprI64AtomicOr,
kExprI64AtomicOr8U, kExprI64AtomicOr16U, kExprI64AtomicOr32U,
kExprI64AtomicXor, kExprI64AtomicXor8U, kExprI64AtomicXor16U,
kExprI64AtomicXor32U, kExprI64AtomicExchange, kExprI64AtomicExchange8U,
kExprI64AtomicExchange16U, kExprI64AtomicExchange32U
];
const opCodeNames = [
"kExprI64AtomicLoad",
"kExprI64AtomicLoad8U",
"kExprI64AtomicLoad16U",
"kExprI64AtomicLoad32U",
"kExprI64AtomicStore",
"kExprI64AtomicStore8U",
"kExprI64AtomicStore16U",
"kExprI64AtomicStore32U",
"kExprI64AtomicAdd",
"kExprI64AtomicAdd8U",
"kExprI64AtomicAdd16U",
"kExprI64AtomicAdd32U",
"kExprI64AtomicSub",
"kExprI64AtomicSub8U",
"kExprI64AtomicSub16U",
"kExprI64AtomicSub32U",
"kExprI64AtomicAnd",
"kExprI64AtomicAnd8U",
"kExprI64AtomicAnd16U",
"kExprI64AtomicAnd32U",
"kExprI64AtomicOr",
"kExprI64AtomicOr8U",
"kExprI64AtomicOr16U",
"kExprI64AtomicOr32U",
"kExprI64AtomicXor",
"kExprI64AtomicXor8U",
"kExprI64AtomicXor16U",
"kExprI64AtomicXor32U",
"kExprI64AtomicExchange",
"kExprI64AtomicExchange8U",
"kExprI64AtomicExchange16U",
"kExprI64AtomicExchange32U"
'kExprI64AtomicLoad', 'kExprI64AtomicLoad8U',
'kExprI64AtomicLoad16U', 'kExprI64AtomicLoad32U',
'kExprI64AtomicStore', 'kExprI64AtomicStore8U',
'kExprI64AtomicStore16U', 'kExprI64AtomicStore32U',
'kExprI64AtomicAdd', 'kExprI64AtomicAdd8U',
'kExprI64AtomicAdd16U', 'kExprI64AtomicAdd32U',
'kExprI64AtomicSub', 'kExprI64AtomicSub8U',
'kExprI64AtomicSub16U', 'kExprI64AtomicSub32U',
'kExprI64AtomicAnd', 'kExprI64AtomicAnd8U',
'kExprI64AtomicAnd16U', 'kExprI64AtomicAnd32U',
'kExprI64AtomicOr', 'kExprI64AtomicOr8U',
'kExprI64AtomicOr16U', 'kExprI64AtomicOr32U',
'kExprI64AtomicXor', 'kExprI64AtomicXor8U',
'kExprI64AtomicXor16U', 'kExprI64AtomicXor32U',
'kExprI64AtomicExchange', 'kExprI64AtomicExchange8U',
'kExprI64AtomicExchange16U', 'kExprI64AtomicExchange32U'
];
let kMaxMemPages = 10;
let gSharedMemory =
new WebAssembly.Memory({initial: 1, maximum: kMaxMemPages, shared: true});
let gSharedMemoryView = new Int32Array(gSharedMemory.buffer);
let gPrivateMemory =
new WebAssembly.Memory({initial: 1, maximum: kMaxMemPages, shared: true});
let gPrivateMemoryView = new Int32Array(gPrivateMemory.buffer);
const kMaxInt32 = (1 << 31) * 2;
class Operation {
......@@ -102,8 +74,8 @@ class Operation {
}
this.low_input = low_input;
this.high_input = high_input;
this.offset = offset != undefined ? offset : Operation.offsetForSize(
this.size);
this.offset =
offset != undefined ? offset : Operation.offsetForSize(this.size);
}
static nextOpcode() {
......@@ -127,14 +99,17 @@ class Operation {
// Avoid 32 bit overflow for integer here :(
return [Math.floor(random * (1 << (size - 1)) * 2), 0];
}
return [Math.floor(Math.random() * kMaxInt32), Math.floor(Math.random() *
kMaxInt32)];
return [
Math.floor(Math.random() * kMaxInt32),
Math.floor(Math.random() * kMaxInt32)
];
}
static offsetForSize(size) {
// Pick an offset in bytes between 0 and 8.
let offset = Math.floor(Math.random() * 8);
// Make sure the offset matches the required alignment by masking out the lower bits.
// Make sure the offset matches the required alignment by masking out the
// lower bits.
let size_in_bytes = size / 8;
let mask = ~(size_in_bytes - 1);
return offset & mask;
......@@ -142,7 +117,10 @@ class Operation {
get wasmOpcode() {
// [opcode, alignment, offset]
return [opCodes[this.opcode], Operation.opcodeToAlignment(this.opcode), this.offset];
return [
opCodes[this.opcode], Operation.opcodeToAlignment(this.opcode),
this.offset
];
}
get hasInput() {
......@@ -150,20 +128,23 @@ class Operation {
}
get hasOutput() {
return this.opcode < kFirstOpcodeWithoutOutput || this.opcode >
kLastOpcodeWithoutOutput;
return this.opcode < kFirstOpcodeWithoutOutput ||
this.opcode > kLastOpcodeWithoutOutput;
}
truncateResultBits(low, high) {
if (this.size == 64) return [low, high]
if (this.size == 64)
return [low, high]
// Shift the lower part. For offsets greater four it drops out of the visible window.
// Shift the lower part. For offsets greater four it drops out of the
// visible window.
let shiftedL = this.offset >= 4 ? 0 : low >>> (this.offset * 8);
// The higher part is zero for offset 0, left shifted for [1..3] and right shifted
// for [4..7].
let shiftedH = this.offset == 0 ? 0 :
this.offset >= 4 ? high >>> (this.offset - 4) * 8 : high << ((4 -
this.offset) * 8);
// The higher part is zero for offset 0, left shifted for [1..3] and right
// shifted for [4..7].
let shiftedH = this.offset == 0 ?
0 :
this.offset >= 4 ? high >>> (this.offset - 4) * 8 :
high << ((4 - this.offset) * 8);
let value = shiftedL | shiftedH;
switch (this.size) {
......@@ -174,15 +155,14 @@ class Operation {
case 32:
return [value, 0];
default:
throw "Unexpected size: " + this.size;
throw 'Unexpected size: ' + this.size;
}
}
static get builder() {
if (!Operation.__builder) {
let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, 1, false);
builder.exportMemoryAs("mem");
builder.addImportedMemory('m', 'imported_mem', 0, kMaxMemPages, 'shared');
Operation.__builder = builder;
}
return Operation.__builder;
......@@ -211,24 +191,21 @@ class Operation {
// Load address of low 32 bits.
kExprI32Const, 0,
// Load expected value.
kExprGetLocal, 0,
kExprI32StoreMem, 2, 0,
kExprGetLocal, 0, kExprI32StoreMem, 2, 0,
// Load address of high 32 bits.
kExprI32Const, 4,
// Load expected value.
kExprGetLocal, 1,
kExprI32StoreMem, 2, 0,
kExprGetLocal, 1, kExprI32StoreMem, 2, 0,
// Load address of where our window starts.
kExprI32Const, 0,
// Load input if there is one.
...(this.hasInput ? [kExprGetLocal, 3,
kExprI64UConvertI32,
kExprI64Const, 32,
kExprI64Shl,
kExprGetLocal, 2,
kExprI64UConvertI32,
...(this.hasInput ?
[
kExprGetLocal, 3, kExprI64UConvertI32, kExprI64Const, 32,
kExprI64Shl, kExprGetLocal, 2, kExprI64UConvertI32,
kExprI64Ior
] : []),
] :
[]),
// Perform operation.
kAtomicPrefix, ...this.wasmOpcode,
// Drop output if it had any.
......@@ -241,28 +218,27 @@ class Operation {
.exportAs(this.key);
// Instantiate module, get function exports.
let module = new WebAssembly.Module(builder.toBuffer());
Operation.instance = new WebAssembly.Instance(module);
Operation.instance =
new WebAssembly.Instance(module, {m: {imported_mem: gPrivateMemory}});
evalFun = Operation.exports[this.key];
}
evalFun(state.low, state.high, this.low_input, this.high_input);
let ta = new Int32Array(Operation.memory.buffer);
let ta = gPrivateMemoryView;
if (kDebug) {
print(state.high + ":" + state.low + " " + this.toString() +
" -> " + ta[1] + ":" + ta[0]);
print(
state.high + ':' + state.low + ' ' + this.toString() + ' -> ' +
ta[1] + ':' + ta[0]);
}
return {
low: ta[0],
high: ta[1]
};
return {low: ta[0], high: ta[1]};
}
toString() {
return opCodeNames[this.opcode] + "[+" + this.offset + "] " + this.high_input +
":" + this.low_input;
return opCodeNames[this.opcode] + '[+' + this.offset + '] ' +
this.high_input + ':' + this.low_input;
}
get key() {
return this.opcode + "-" + this.offset;
return this.opcode + '-' + this.offset;
}
}
......@@ -279,7 +255,7 @@ class State {
}
toString() {
return this.high + ":" + this.low + " @ " + this.indices;
return this.high + ':' + this.low + ' @ ' + this.indices;
}
}
......@@ -304,8 +280,8 @@ function toSLeb128(low, high) {
high = high >> 7;
}
let msbIsSet = (v & 0x40) || false;
if (((low == 0) && (high == 0) && !msbIsSet) || ((low == -1) && (high ==
-1) && msbIsSet)) {
if (((low == 0) && (high == 0) && !msbIsSet) ||
((low == -1) && (high == -1) && msbIsSet)) {
result.push(v);
break;
}
......@@ -323,18 +299,12 @@ function generateFunctionBodyForSequence(sequence) {
if (!kDebug) {
body.push(
// Decrement the wait count.
kExprGetLocal, 2,
kExprI32Const, 1,
kAtomicPrefix, kExprI32AtomicSub, 2, 0,
kExprGetLocal, 2, kExprI32Const, 1, kAtomicPrefix, kExprI32AtomicSub, 2,
0,
// Spin until zero.
kExprLoop, kWasmStmt,
kExprGetLocal, 2,
kAtomicPrefix, kExprI32AtomicLoad, 2, 0,
kExprI32Const, 0,
kExprI32GtU,
kExprBrIf, 0,
kExprEnd
);
kExprLoop, kWasmStmt, kExprGetLocal, 2, kAtomicPrefix,
kExprI32AtomicLoad, 2, 0, kExprI32Const, 0, kExprI32GtU, kExprBrIf, 0,
kExprEnd);
}
for (let operation of sequence) {
body.push(
......@@ -343,8 +313,12 @@ function generateFunctionBodyForSequence(sequence) {
// Load address where atomic pointers are stored.
kExprGetLocal, 0,
// Load the second argument if it had any.
...(operation.hasInput ? [kExprI64Const, ...toSLeb128(operation
.low_input, operation.high_input)] : []),
...(operation.hasInput ?
[
kExprI64Const,
...toSLeb128(operation.low_input, operation.high_input)
] :
[]),
// Perform operation
kAtomicPrefix, ...operation.wasmOpcode,
// Generate fake output in needed.
......@@ -352,21 +326,17 @@ function generateFunctionBodyForSequence(sequence) {
// Store read intermediate to sequence.
kExprI64StoreMem, 3, 0,
// Increment result sequence pointer.
kExprGetLocal, 1,
kExprI32Const, 8,
kExprI32Add,
kExprSetLocal, 1
);
kExprGetLocal, 1, kExprI32Const, 8, kExprI32Add, kExprSetLocal, 1);
}
// Return end of sequence index.
body.push(
kExprGetLocal, 1,
kExprReturn);
body.push(kExprGetLocal, 1, kExprReturn);
return body;
}
function getSequence(start, end) {
return new Int32Array(memory.buffer, start, (end - start) / Int32Array.BYTES_PER_ELEMENT);
return new Int32Array(
gSharedMemory.buffer, start,
(end - start) / Int32Array.BYTES_PER_ELEMENT);
}
function spawnWorkers() {
......@@ -387,8 +357,8 @@ function spawnWorkers() {
let result = instance.exports["worker" + index](address, sequence, spin);
postMessage({index: index, sequence: sequence, result: result});
}
}`, {type: 'string'}
);
}`,
{type: 'string'});
workers.push(worker);
}
return workers;
......@@ -396,12 +366,9 @@ function spawnWorkers() {
function instantiateModuleInWorkers(workers) {
for (let worker of workers) {
worker.postMessage({
module: module,
mem: memory
});
worker.postMessage({module: module, mem: gSharedMemory});
let msg = worker.getMessage();
if (!msg.instantiated) throw "Worker failed to instantiate";
if (!msg.instantiated) throw 'Worker failed to instantiate';
}
}
......@@ -430,11 +397,12 @@ function selectMatchingWorkers(state) {
if (index >= kSequenceLength) continue;
// We need to project the expected value to the number of bits this
// operation will read at runtime.
let [expected_low, expected_high] = sequences[i][index].truncateResultBits(
state.low, state.high);
let [expected_low, expected_high] =
sequences[i][index].truncateResultBits(state.low, state.high);
let hasOutput = sequences[i][index].hasOutput;
if (!hasOutput || ((results[i][index * 2] == expected_low) && (results[
i][index * 2 + 1] == expected_high))) {
if (!hasOutput ||
((results[i][index * 2] == expected_low) &&
(results[i][index * 2 + 1] == expected_high))) {
matching.push(i);
}
}
......@@ -446,10 +414,7 @@ function computeNextState(state, advanceIdx) {
let sequence = sequences[advanceIdx];
let operation = sequence[state.indices[advanceIdx]];
newIndices[advanceIdx]++;
let {
low,
high
} = operation.compute(state);
let {low, high} = operation.compute(state);
return new State(low, high, newIndices, state.count + 1);
}
......@@ -476,7 +441,7 @@ function findSequentialOrdering() {
matchingStates.push(newState);
}
if (steps++ > kNumberOfSteps) {
print("Search timed out, aborting...");
print('Search timed out, aborting...');
return true;
}
}
......@@ -493,12 +458,12 @@ function loadSequencesFromStrings(inputs) {
let sequences = [];
let parseRE = /([a-zA-Z0-9]*)\[\+([0-9])\] ([\-0-9]*)/;
for (let input of inputs) {
let parts = input.split(",");
let parts = input.split(',');
let sequence = [];
for (let part of parts) {
let parsed = parseRE.exec(part);
sequence.push(new Operation(reverseOpcodes[parsed[1]], parsed[3],
parsed[2] | 0));
sequence.push(
new Operation(reverseOpcodes[parsed[1]], parsed[3], parsed[2] | 0));
}
sequences.push(sequence);
}
......@@ -509,7 +474,7 @@ function loadSequencesFromStrings(inputs) {
function loadResultsFromStrings(inputs) {
let results = [];
for (let input of inputs) {
let parts = input.split(",");
let parts = input.split(',');
let result = [];
for (let number of parts) {
result.push(number | 0);
......@@ -519,39 +484,28 @@ function loadResultsFromStrings(inputs) {
return results;
}
let maxSize = 10;
let memory = new WebAssembly.Memory({
initial: 1,
maximum: maxSize,
shared: true
});
let memory_view = new Int32Array(memory.buffer);
let sequences = [];
let results = [];
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "imported_mem", 0, maxSize, "shared");
builder.addImportedMemory('m', 'imported_mem', 0, kMaxMemPages, 'shared');
for (let i = 0; i < kNumberOfWorker; i++) {
sequences[i] = makeSequenceOfOperations(kSequenceLength);
builder.addFunction("worker" + i, kSig_i_iii)
builder.addFunction('worker' + i, kSig_i_iii)
.addBody(generateFunctionBodyForSequence(sequences[i]))
.exportAs("worker" + i);
.exportAs('worker' + i);
}
// Instantiate module, get function exports.
let module = new WebAssembly.Module(builder.toBuffer());
let instance = new WebAssembly.Instance(module, {
m: {
imported_mem: memory
}
});
let instance =
new WebAssembly.Instance(module, {m: {imported_mem: gSharedMemory}});
// Spawn off the workers and run the sequences.
let workers = spawnWorkers();
// Set spin count.
memory_view[4] = kNumberOfWorker;
gSharedMemoryView[4] = kNumberOfWorker;
instantiateModuleInWorkers(workers);
executeSequenceInWorkers(workers);
......@@ -583,13 +537,13 @@ if (kDebug) {
let passed = findSequentialOrdering();
if (passed) {
print("PASS");
print('PASS');
} else {
for (let i = 0; i < kNumberOfWorker; i++) {
print("Worker " + i);
print('Worker ' + i);
print(sequences[i]);
print(results[i]);
}
print("FAIL");
print('FAIL');
quit(-1);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment