// 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);
