import Builder from '../Builder.js';
import * as assert from '../assert.js';
import * as LLB from '../LowLevelBinary.js';
import * as WASM from '../WASM.js';
import * as util from '../utilities.js';

const verbose = false;

const pageSize = 64 * 1024;
const fourGiB = pageSize * 65536;
const initial = 64;
const maximum = 128;

// When using fast memories, we allocate a redzone after the 4GiB huge
// allocation. This redzone is used to trap reg+imm accesses which exceed
// 32-bits. Anything past 4GiB must trap, but we cannot know statically that it
// will.

const offsets = [
    0,
    1,
    2,
    1024,
    pageSize,
    pageSize + pageSize / 2,
    pageSize * 8,
    pageSize * 16,
    pageSize * 128,
    pageSize * 512,
    fourGiB / 4 - 4,
    fourGiB / 4 - 3,
    fourGiB / 4 - 2,
    fourGiB / 4 - 1,
    fourGiB / 4,
    fourGiB / 4 + 1,
    fourGiB / 4 + 2,
    fourGiB / 4 + 3,
    fourGiB / 4 + 4,
    fourGiB / 2 - 4,
    fourGiB / 2 - 3,
    fourGiB / 2 - 2,
    fourGiB / 2 - 1,
    fourGiB / 2,
    fourGiB / 2 + 1,
    fourGiB / 2 + 2,
    fourGiB / 2 + 3,
    fourGiB / 2 + 4,
    (fourGiB / 4) * 3,
    fourGiB - 4,
    fourGiB - 3,
    fourGiB - 2,
    fourGiB - 1,
];

for (let memoryDeclaration of [{ initial: initial }, { initial: initial, maximum: maximum }]) {
    fullGC();

    // Re-use a single memory so tests are more likely to get a fast memory.
    const memory = new WebAssembly.Memory(memoryDeclaration);
    if (verbose)
        print(WebAssemblyMemoryMode(memory));
    const buf = new Uint8Array(memory.buffer);

    // Enumerate all memory access types.
    for (const op of WASM.opcodes("memory")) {
        const info = WASM.memoryAccessInfo(op);

        // The accesses should fault even if only the last byte is off the end.
        let wiggles = [0];
        for (let wiggle = 0; wiggle !== info.width / 8; ++wiggle)
            wiggles.push(wiggle);

        let builder = (new Builder())
            .Type().End()
            .Import().Memory("imp", "memory", memoryDeclaration).End()
            .Function().End()
            .Export();

        for (let offset of offsets)
            switch (info.type) {
            case "load": builder = builder.Function("get_" + offset); break;
            case "store": builder = builder.Function("set_" + offset); break;
            default: throw new Error(`Implementation problem: unknown memory access type ${info.type}`);
            }

        builder = builder.End().Code();

        const align = 0; // No need to be precise, it's just a hint.
        const constInstr = util.toJavaScriptName(WASM.constForValueType(info.valueType));
        const instr = util.toJavaScriptName(op.name);
        for (let offset of offsets)
            switch (info.type) {
            case "load":
                builder = builder.Function("get_" + offset, { params: ["i32"] }).GetLocal(0)[instr](align, offset).Drop().End();
                break;
            case "store":
                builder = builder.Function("set_" + offset, { params: ["i32"] }).GetLocal(0)[constInstr](0xdead)[instr](align, offset).End();
                break;
            default:
                throw new Error(`Implementation problem: unknown memory access type ${info.type}`);
            }
        
        builder = builder.End();

        const instance = new WebAssembly.Instance(new WebAssembly.Module(builder.WebAssembly().get()), { imp: { memory: memory } });

        for (let offset of offsets) {
            for (let wiggle of wiggles) {
                const address = LLB.varuint32Max - offset - wiggle;
                if (verbose)
                    print(`${op.name.padStart(16, ' ')}: base address ${address > 0 ? '0x' : '  '}${address.toString(16).padStart(8, address > 0 ? '0' : ' ')} + offset 0x${offset.toString(16).padStart(8, '0')} - wiggle ${wiggle} = effective address 0x${(address + offset - wiggle).toString(16).padStart(16, '0')}`);
                switch (info.type) {
                case "load":
                    assert.throws(() => instance.exports["get_" + offset](address), WebAssembly.RuntimeError, `Out of bounds memory access`);
                    break;
                case "store":
                    assert.throws(() => instance.exports["set_" + offset](address), WebAssembly.RuntimeError, `Out of bounds memory access`);
                    break;
                default: throw new Error(`Implementation problem: unknown memory access type ${info.type}`);
                }
            }
        }

        fullGC();
    }

    // Only check that the memory was untouched at the very end, before throwing it away entirely.
    for (let idx = 0; idx < buf.byteLength; ++idx)
        assert.eq(buf[idx], 0);
}
