Search in sources :

Example 1 with WasmContext

use of org.graalvm.wasm.WasmContext in project graal by oracle.

the class RunCustomInitializationNode method initializeModule.

@SuppressWarnings("unchecked")
@CompilerDirectives.TruffleBoundary
private static void initializeModule(Object initialization) {
    if (initialization != null) {
        WasmContext context = WasmContext.get(null);
        ((Consumer<WasmContext>) initialization).accept(context);
    }
}
Also used : WasmContext(org.graalvm.wasm.WasmContext) Consumer(java.util.function.Consumer)

Example 2 with WasmContext

use of org.graalvm.wasm.WasmContext in project graal by oracle.

the class WasmJsApiSuite method testTableInstanceOutOfBoundsSet.

@Test
public void testTableInstanceOutOfBoundsSet() throws IOException {
    runTest(context -> {
        final WebAssembly wasm = new WebAssembly(context);
        final WasmInstance instance = moduleInstantiate(wasm, binaryWithMixedExports, null);
        final InteropLibrary lib = InteropLibrary.getUncached();
        WasmContext wasmContext = WasmContext.get(null);
        final WasmFunctionInstance functionInstance = new WasmFunctionInstance(wasmContext, null, new RootNode(wasmContext.language()) {

            @Override
            public Object execute(VirtualFrame frame) {
                return 42;
            }
        }.getCallTarget());
        // We should be able to set element 1.
        try {
            final Object table = WebAssembly.instanceExport(instance, "t");
            final Object writeTable = wasm.readMember("table_write");
            lib.execute(writeTable, table, 0, functionInstance);
        } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException | ArityException e) {
            throw new RuntimeException(e);
        }
        // But not element 2.
        try {
            final Object table = WebAssembly.instanceExport(instance, "t");
            final Object writeTable = wasm.readMember("table_write");
            lib.execute(writeTable, table, 1, functionInstance);
            Assert.fail("Should have failed - export count exceeds the limit");
        } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException | ArityException e) {
            throw new RuntimeException(e);
        } catch (WasmJsApiException e) {
            Assert.assertEquals("Range error expected", WasmJsApiException.Kind.RangeError, e.kind());
        }
    });
}
Also used : WasmInstance(org.graalvm.wasm.WasmInstance) RootNode(com.oracle.truffle.api.nodes.RootNode) WasmJsApiException(org.graalvm.wasm.exception.WasmJsApiException) WebAssembly(org.graalvm.wasm.api.WebAssembly) ArityException(com.oracle.truffle.api.interop.ArityException) VirtualFrame(com.oracle.truffle.api.frame.VirtualFrame) WasmContext(org.graalvm.wasm.WasmContext) UnsupportedMessageException(com.oracle.truffle.api.interop.UnsupportedMessageException) UnknownIdentifierException(com.oracle.truffle.api.interop.UnknownIdentifierException) InteropLibrary(com.oracle.truffle.api.interop.InteropLibrary) UnsupportedTypeException(com.oracle.truffle.api.interop.UnsupportedTypeException) TruffleObject(com.oracle.truffle.api.interop.TruffleObject) WasmFunctionInstance(org.graalvm.wasm.WasmFunctionInstance) Test(org.junit.Test)

Example 3 with WasmContext

use of org.graalvm.wasm.WasmContext in project graal by oracle.

the class WasmFileSuite method runInContext.

private static void runInContext(WasmCase testCase, Context context, List<Source> sources, int iterations, String phaseIcon, String phaseLabel) throws IOException {
    try {
        // Whereas the test needs memory to be reset between iterations.
        final boolean requiresZeroMemory = Boolean.parseBoolean(testCase.options().getProperty("zero-memory", "false"));
        resetStatus(System.out, PHASE_PARSE_ICON, "parsing");
        // This is needed so that we can call WasmContext.getCurrent().
        context.enter();
        try {
            sources.forEach(context::eval);
        } catch (PolyglotException e) {
            validateThrown(testCase.data(), WasmCaseData.ErrorType.Validation, e);
            return;
        }
        final WasmContext wasmContext = WasmContext.get(null);
        final Value mainFunction = findMain(wasmContext);
        resetStatus(System.out, phaseIcon, phaseLabel);
        final String argString = testCase.options().getProperty("argument");
        final Integer arg = argString == null ? null : Integer.parseInt(argString);
        ContextState firstIterationContextState = null;
        for (int i = 0; i != iterations; ++i) {
            try {
                TEST_OUT.reset();
                final Value result = arg == null ? mainFunction.execute() : mainFunction.execute(arg);
                WasmCase.validateResult(testCase.data().resultValidator(), result, TEST_OUT);
            } catch (PolyglotException e) {
                // then we check stdout.
                if (e.isExit() && testCase.data().expectedErrorMessage() == null) {
                    Assert.assertEquals("Program exited with non-zero return code.", e.getExitStatus(), 0);
                    WasmCase.validateResult(testCase.data().resultValidator(), null, TEST_OUT);
                } else if (testCase.data().expectedErrorTime() == WasmCaseData.ErrorType.Validation) {
                    validateThrown(testCase.data(), WasmCaseData.ErrorType.Validation, e);
                    return;
                } else {
                    validateThrown(testCase.data(), WasmCaseData.ErrorType.Runtime, e);
                }
            } catch (Throwable t) {
                final RuntimeException e = new RuntimeException("Error during test phase '" + phaseLabel + "'", t);
                e.setStackTrace(new StackTraceElement[0]);
                throw e;
            } finally {
                // Save context state, and check that it's consistent with the previous one.
                if (iterationNeedsStateCheck(i)) {
                    final ContextState contextState = saveContext(wasmContext);
                    if (firstIterationContextState == null) {
                        firstIterationContextState = contextState;
                    } else {
                        assertContextEqual(firstIterationContextState, contextState);
                    }
                }
                // Reset context state.
                final boolean reinitMemory = requiresZeroMemory || iterationNeedsStateCheck(i + 1);
                if (reinitMemory) {
                    for (int j = 0; j < wasmContext.memories().count(); ++j) {
                        wasmContext.memories().memory(j).reset();
                    }
                    for (int j = 0; j < wasmContext.tables().tableCount(); ++j) {
                        wasmContext.tables().table(j).reset();
                    }
                }
                for (final WasmInstance instance : wasmContext.moduleInstances().values()) {
                    if (!instance.isBuiltin()) {
                        wasmContext.reinitInstance(instance, reinitMemory);
                    }
                }
                // Reset stdin
                if (wasmContext.environment().in() instanceof ByteArrayInputStream) {
                    wasmContext.environment().in().reset();
                }
            }
        }
    } finally {
        System.setOut(System.out);
        context.close(true);
    }
}
Also used : WasmInstance(org.graalvm.wasm.WasmInstance) PolyglotException(org.graalvm.polyglot.PolyglotException) WasmContext(org.graalvm.wasm.WasmContext) ByteArrayInputStream(java.io.ByteArrayInputStream) Value(org.graalvm.polyglot.Value)

Example 4 with WasmContext

use of org.graalvm.wasm.WasmContext in project graal by oracle.

the class WasmJsApiSuite method runTest.

private static void runTest(Consumer<WasmContext> testCase) throws IOException {
    final Context.Builder contextBuilder = Context.newBuilder(WasmLanguage.ID);
    contextBuilder.option("wasm.Builtins", "testutil:testutil");
    final Context context = contextBuilder.build();
    Source.Builder sourceBuilder = Source.newBuilder(WasmLanguage.ID, ByteSequence.create(binaryWithExports), "main");
    Source source = sourceBuilder.build();
    context.eval(source);
    Value main = context.getBindings(WasmLanguage.ID).getMember("main").getMember("main");
    main.execute();
    Value run = context.getBindings(WasmLanguage.ID).getMember("testutil").getMember(TestutilModule.Names.RUN_CUSTOM_INITIALIZATION);
    run.execute(new GuestCode(testCase));
}
Also used : WasmContext(org.graalvm.wasm.WasmContext) Context(org.graalvm.polyglot.Context) Value(org.graalvm.polyglot.Value) Source(org.graalvm.polyglot.Source)

Example 5 with WasmContext

use of org.graalvm.wasm.WasmContext in project graal by oracle.

the class WasmBlockNode method execute.

@Override
@BytecodeInterpreterSwitch
@BytecodeInterpreterSwitchBoundary
@ExplodeLoop(kind = ExplodeLoop.LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN)
@SuppressWarnings("UnusedAssignment")
public int execute(WasmContext context, VirtualFrame frame) {
    final WasmCodeEntry codeEntry = codeEntry();
    final int numLocals = codeEntry.numLocals();
    final byte[] data = codeEntry.data();
    final int[] intConstants = codeEntry.intConstants();
    final int[] profileCounters = codeEntry.profileCounters();
    final int blockByteLength = byteLength();
    final int offsetLimit = startOffset + blockByteLength;
    int childrenOffset = 0;
    int intConstantOffset = initialIntConstantOffset;
    int branchTableOffset = initialBranchTableOffset;
    int stackPointer = numLocals + initialStackPointer;
    int profileOffset = initialProfileOffset;
    int offset = startOffset;
    WasmMemory memory = instance().memory();
    check(data.length, (1 << 31) - 1);
    check(intConstants.length, (1 << 31) - 1);
    check(profileCounters.length, (1 << 31) - 1);
    int opcode = UNREACHABLE;
    while (offset < offsetLimit) {
        byte byteOpcode = BinaryStreamParser.rawPeek1(data, offset);
        opcode = byteOpcode & 0xFF;
        offset++;
        CompilerAsserts.partialEvaluationConstant(offset);
        switch(opcode) {
            case UNREACHABLE:
                errorBranch();
                throw WasmException.create(Failure.UNREACHABLE, this);
            case NOP:
                break;
            case BLOCK:
                {
                    WasmBlockNode block = (WasmBlockNode) children[childrenOffset];
                    // The unwind counter indicates how many levels up we need to branch from
                    // within the block.
                    int unwindCounter = block.execute(context, frame);
                    if (blockUnwindProfile.profile(unwindCounter > 0)) {
                        return unwindCounter - 1;
                    }
                    childrenOffset++;
                    offset += block.byteLength();
                    stackPointer += block.returnLength();
                    intConstantOffset += block.intConstantLength();
                    branchTableOffset += block.branchTableLength();
                    profileOffset += block.profileCount();
                    break;
                }
            case LOOP:
                {
                    LoopNode loopNode = (LoopNode) children[childrenOffset];
                    final WasmBlockNode loopBody = (WasmBlockNode) loopNode.getRepeatingNode();
                    // The unwind counter indicates how many levels up we need to branch from
                    // within the loop block.
                    // There are three possibilities for the value of unwind counter:
                    // - A value equal to -1 indicates normal loop completion and that the flow
                    // should continue after the loop end (break out of the loop).
                    // - A value equal to 0 indicates that we need to branch to the beginning of
                    // the loop (repeat loop).
                    // This is handled internally by Truffle and the executing loop should never
                    // return 0 here.
                    // - A value larger than 0 indicates that we need to branch to a level
                    // "shallower" than the current loop block
                    // (break out of the loop and even further).
                    int unwindCounter = executeLoopNode(childrenOffset, frame);
                    if (loopUnwindProfile.profile(unwindCounter > 0)) {
                        return unwindCounter - 1;
                    }
                    // The unwind counter cannot be 0 at this point.
                    assert unwindCounter == -1 : "Unwind counter after loop exit: " + unwindCounter;
                    childrenOffset++;
                    offset += loopBody.byteLength();
                    stackPointer += loopBody.returnLength();
                    intConstantOffset += loopBody.intConstantLength();
                    branchTableOffset += loopBody.branchTableLength();
                    profileOffset += loopBody.profileCount();
                    break;
                }
            case IF:
                {
                    WasmIfNode ifNode = (WasmIfNode) children[childrenOffset];
                    stackPointer--;
                    int unwindCounter = ifNode.execute(context, frame);
                    if (ifUnwindProfile.profile(unwindCounter > 0)) {
                        return unwindCounter - 1;
                    }
                    childrenOffset++;
                    offset += ifNode.byteLength();
                    stackPointer += ifNode.returnLength();
                    intConstantOffset += ifNode.intConstantLength();
                    branchTableOffset += ifNode.branchTableLength();
                    profileOffset += ifNode.profileCount();
                    break;
                }
            case ELSE:
                break;
            case END:
                break;
            case BR:
                {
                    // region Load LEB128 Unsigned32 -> unwindCounter
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int unwindCounter = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    // Reset the stack pointer to the target block stack pointer.
                    // region Load int continuationStackPointer
                    int continuationStackPointer = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    // region Load int targetBlockReturnLength
                    int targetBlockReturnLength = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    // Populate the stack with the return values of the current block (the one
                    // we are escaping from).
                    unwindStack(frame, stackPointer, numLocals + continuationStackPointer, targetBlockReturnLength);
                    return unwindCounter;
                }
            case BR_IF:
                {
                    stackPointer--;
                    // region Load LEB128 Unsigned32 -> unwindCounter
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int unwindCounter = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    // region Load int continuationStackPointer
                    int continuationStackPointer = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    // region Load int targetBlockReturnLength
                    int targetBlockReturnLength = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    boolean condition = WasmCodeEntry.profileCondition(profileCounters, profileOffset, popBoolean(frame, stackPointer));
                    ++profileOffset;
                    if (condition) {
                        // Populate the stack with the return values of the current block (the
                        // one we are escaping from).
                        unwindStack(frame, stackPointer, numLocals + continuationStackPointer, targetBlockReturnLength);
                        return unwindCounter;
                    }
                    break;
                }
            case BR_TABLE:
                {
                    stackPointer--;
                    int index = popInt(frame, stackPointer);
                    int[] table = codeEntry.branchTable(branchTableOffset);
                    index = index < 0 || index >= (table.length - 1) / 2 ? (table.length - 1) / 2 - 1 : index;
                    // Technically, we should increment the branchTableOffset at this point,
                    // but since we are returning, it does not really matter.
                    int returnTypeLength = table[0];
                    for (int i = 0; i < (table.length - 1) / 2; ++i) {
                        if (i == index) {
                            int unwindCounter = table[1 + 2 * i];
                            int continuationStackPointer = table[1 + 2 * i + 1];
                            // Populate the stack with the return values of the current block
                            // (the one we are escaping from).
                            unwindStack(frame, stackPointer, numLocals + continuationStackPointer, returnTypeLength);
                            return unwindCounter;
                        }
                    }
                    errorBranch();
                    throw WasmException.create(Failure.UNSPECIFIED_INTERNAL, this, "Should not reach here");
                }
            case RETURN:
                {
                    // A return statement causes the termination of the current function, i.e.
                    // causes the execution to resume after the instruction that invoked
                    // the current frame.
                    // region Load int unwindCounterValue
                    int unwindCounter = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    // region Load int rootBlockReturnLength
                    int rootBlockReturnLength = intConstants[intConstantOffset];
                    intConstantOffset++;
                    // endregion
                    unwindStack(frame, stackPointer, numLocals, rootBlockReturnLength);
                    return unwindCounter;
                }
            case CALL:
                {
                    // region Load LEB128 Unsigned32 -> functionIndex
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int functionIndex = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    WasmFunction function = instance().symbolTable().function(functionIndex);
                    byte returnType = function.returnType();
                    CompilerAsserts.partialEvaluationConstant(returnType);
                    int numArgs = function.numArguments();
                    Object[] args = createArgumentsForCall(frame, function.typeIndex(), numArgs, stackPointer);
                    stackPointer -= args.length;
                    Object result = executeDirectCall(childrenOffset, function, args);
                    childrenOffset++;
                    // this restriction may be lifted in the future.
                    switch(returnType) {
                        case WasmType.I32_TYPE:
                            {
                                pushInt(frame, stackPointer, (int) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.I64_TYPE:
                            {
                                pushLong(frame, stackPointer, (long) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.F32_TYPE:
                            {
                                pushFloat(frame, stackPointer, (float) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.F64_TYPE:
                            {
                                pushDouble(frame, stackPointer, (double) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.VOID_TYPE:
                            {
                                // Void return type - do nothing.
                                break;
                            }
                        default:
                            {
                                throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown return type: %d", returnType);
                            }
                    }
                    break;
                }
            case CALL_INDIRECT:
                {
                    // Extract the function object.
                    stackPointer--;
                    final SymbolTable symtab = instance().symbolTable();
                    final WasmTable table = instance().table();
                    final Object[] elements = table.elements();
                    final int elementIndex = popInt(frame, stackPointer);
                    if (elementIndex < 0 || elementIndex >= elements.length) {
                        errorBranch();
                        throw WasmException.format(Failure.UNDEFINED_ELEMENT, this, "Element index '%d' out of table bounds.", elementIndex);
                    }
                    // Currently, table elements may only be functions.
                    // We can add a check here when this changes in the future.
                    final Object element = elements[elementIndex];
                    if (element == null) {
                        errorBranch();
                        throw WasmException.format(Failure.UNINITIALIZED_ELEMENT, this, "Table element at index %d is uninitialized.", elementIndex);
                    }
                    final WasmFunctionInstance functionInstance;
                    final WasmFunction function;
                    final CallTarget target;
                    final WasmContext functionInstanceContext;
                    if (element instanceof WasmFunctionInstance) {
                        functionInstance = (WasmFunctionInstance) element;
                        function = functionInstance.function();
                        target = functionInstance.target();
                        functionInstanceContext = functionInstance.context();
                    } else {
                        errorBranch();
                        throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown table element type: %s", element);
                    }
                    // Extract the function type index.
                    // region Load LEB128 Unsigned32 -> expectedFunctionTypeIndex
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int expectedFunctionTypeIndex = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    int expectedTypeEquivalenceClass = symtab.equivalenceClass(expectedFunctionTypeIndex);
                    // Consume the ZERO_TABLE constant at the end of the CALL_INDIRECT
                    // instruction.
                    offset += 1;
                    // Validate that the function type matches the expected type.
                    boolean functionFromCurrentContext = WasmCodeEntry.profileCondition(profileCounters, profileOffset++, functionInstanceContext == context);
                    if (functionFromCurrentContext) {
                        // We can do a quick equivalence-class check.
                        if (expectedTypeEquivalenceClass != function.typeEquivalenceClass()) {
                            errorBranch();
                            failFunctionTypeCheck(function, expectedFunctionTypeIndex);
                        }
                    } else {
                        // provided externally (e.g. comes from a different language).
                        if (function != null && !function.type().equals(symtab.typeAt(expectedFunctionTypeIndex))) {
                            errorBranch();
                            failFunctionTypeCheck(function, expectedFunctionTypeIndex);
                        }
                    }
                    // Invoke the resolved function.
                    int numArgs = instance().symbolTable().functionTypeArgumentCount(expectedFunctionTypeIndex);
                    Object[] args = createArgumentsForCall(frame, expectedFunctionTypeIndex, numArgs, stackPointer);
                    stackPointer -= args.length;
                    // Enter function's context when it is not from the current one
                    final boolean enterContext = !functionFromCurrentContext;
                    TruffleContext truffleContext;
                    Object prev;
                    if (enterContext) {
                        truffleContext = functionInstanceContext.environment().getContext();
                        prev = truffleContext.enter(this);
                    } else {
                        truffleContext = null;
                        prev = null;
                    }
                    final Object result;
                    try {
                        result = executeIndirectCallNode(childrenOffset, target, args);
                    } finally {
                        if (enterContext) {
                            truffleContext.leave(this, prev);
                        }
                    }
                    childrenOffset++;
                    // At the moment, WebAssembly functions may return up to one value.
                    // As per the WebAssembly specification, this restriction may be lifted in
                    // the future.
                    byte returnType = instance().symbolTable().functionTypeReturnType(expectedFunctionTypeIndex);
                    CompilerAsserts.partialEvaluationConstant(returnType);
                    switch(returnType) {
                        case WasmType.I32_TYPE:
                            {
                                pushInt(frame, stackPointer, (int) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.I64_TYPE:
                            {
                                pushLong(frame, stackPointer, (long) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.F32_TYPE:
                            {
                                pushFloat(frame, stackPointer, (float) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.F64_TYPE:
                            {
                                pushDouble(frame, stackPointer, (double) result);
                                stackPointer++;
                                break;
                            }
                        case WasmType.VOID_TYPE:
                            {
                                // Void return type - do nothing.
                                break;
                            }
                        default:
                            {
                                throw WasmException.format(Failure.UNSPECIFIED_TRAP, this, "Unknown return type: %d", returnType);
                            }
                    }
                    break;
                }
            case DROP:
                {
                    stackPointer--;
                    drop(frame, stackPointer);
                    break;
                }
            case SELECT:
                {
                    int cond = popInt(frame, stackPointer - 1);
                    if (cond != 0) {
                        drop(frame, stackPointer - 2);
                    } else {
                        WasmFrame.copy(frame, stackPointer - 2, stackPointer - 3);
                        drop(frame, stackPointer - 2);
                    }
                    stackPointer -= 2;
                    break;
                }
            case LOCAL_GET:
                {
                    // region Load LEB128 Unsigned32 -> index
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int index = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    local_get(frame, stackPointer, index);
                    stackPointer++;
                    break;
                }
            case LOCAL_SET:
                {
                    // region Load LEB128 Unsigned32 -> index
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int index = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    stackPointer--;
                    local_set(frame, stackPointer, index);
                    break;
                }
            case LOCAL_TEE:
                {
                    // region Load LEB128 Unsigned32 -> index
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int index = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    local_tee(frame, stackPointer - 1, index);
                    break;
                }
            case GLOBAL_GET:
                {
                    // region Load LEB128 Unsigned32 -> index
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int index = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    global_get(context, frame, stackPointer, index);
                    stackPointer++;
                    break;
                }
            case GLOBAL_SET:
                {
                    // region Load LEB128 Unsigned32 -> index
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int index = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    stackPointer--;
                    global_set(context, frame, stackPointer, index);
                    break;
                }
            case I32_LOAD:
                {
                    /* The memAlign hint is not currently used or taken into account. */
                    int memAlignOffsetDelta = offsetDelta(data, offset);
                    offset += memAlignOffsetDelta;
                    // region Load LEB128 Unsigned32 -> memOffset
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int memOffset = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    int baseAddress = popInt(frame, stackPointer - 1);
                    final long address = effectiveMemoryAddress(memOffset, baseAddress);
                    int value = memory.load_i32(this, address);
                    pushInt(frame, stackPointer - 1, value);
                    break;
                }
            case I64_LOAD:
            case F32_LOAD:
            case F64_LOAD:
            case I32_LOAD8_S:
            case I32_LOAD8_U:
            case I32_LOAD16_S:
            case I32_LOAD16_U:
            case I64_LOAD8_S:
            case I64_LOAD8_U:
            case I64_LOAD16_S:
            case I64_LOAD16_U:
            case I64_LOAD32_S:
            case I64_LOAD32_U:
                {
                    /* The memAlign hint is not currently used or taken into account. */
                    int memAlignOffsetDelta = offsetDelta(data, offset);
                    offset += memAlignOffsetDelta;
                    // region Load LEB128 Unsigned32 -> memOffset
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int memOffset = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    load(memory, frame, stackPointer - 1, opcode, memOffset);
                    break;
                }
            case I32_STORE:
            case I64_STORE:
            case F32_STORE:
            case F64_STORE:
            case I32_STORE_8:
            case I32_STORE_16:
            case I64_STORE_8:
            case I64_STORE_16:
            case I64_STORE_32:
                {
                    /* The memAlign hint is not currently used or taken into account. */
                    int memAlignOffsetDelta = offsetDelta(data, offset);
                    offset += memAlignOffsetDelta;
                    // region Load LEB128 Unsigned32 -> memOffset
                    long valueLength = unsignedIntConstantAndLength(data, offset);
                    int memOffset = value(valueLength);
                    int offsetDelta = length(valueLength);
                    offset += offsetDelta;
                    // endregion
                    store(memory, frame, stackPointer, opcode, memOffset);
                    stackPointer -= 2;
                    break;
                }
            case MEMORY_SIZE:
                {
                    // Skip the 0x00 constant.
                    offset++;
                    int pageSize = memory.size();
                    pushInt(frame, stackPointer, pageSize);
                    stackPointer++;
                    break;
                }
            case MEMORY_GROW:
                {
                    // Skip the 0x00 constant.
                    offset++;
                    stackPointer--;
                    int extraSize = popInt(frame, stackPointer);
                    int pageSize = memory.size();
                    if (memory.grow(extraSize)) {
                        pushInt(frame, stackPointer, pageSize);
                        stackPointer++;
                    } else {
                        pushInt(frame, stackPointer, -1);
                        stackPointer++;
                    }
                    break;
                }
            case I32_CONST:
                {
                    // region Load LEB128 Signed32 -> value
                    long valueAndLength = signedIntConstantAndLength(data, offset);
                    int offsetDelta = length(valueAndLength);
                    offset += offsetDelta;
                    // endregion
                    pushInt(frame, stackPointer, value(valueAndLength));
                    stackPointer++;
                    break;
                }
            case I64_CONST:
                {
                    // region Load LEB128 Signed64 -> value
                    long value = signedLongConstant(data, offset);
                    int offsetDelta = offsetDelta(data, offset);
                    offset += offsetDelta;
                    // endregion
                    pushLong(frame, stackPointer, value);
                    stackPointer++;
                    break;
                }
            case I32_EQZ:
                i32_eqz(frame, stackPointer);
                break;
            case I32_EQ:
                i32_eq(frame, stackPointer);
                stackPointer--;
                break;
            case I32_NE:
                i32_ne(frame, stackPointer);
                stackPointer--;
                break;
            case I32_LT_S:
                i32_lt_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_LT_U:
                i32_lt_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_GT_S:
                i32_gt_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_GT_U:
                i32_gt_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_LE_S:
                i32_le_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_LE_U:
                i32_le_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_GE_S:
                i32_ge_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_GE_U:
                i32_ge_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_EQZ:
                i64_eqz(frame, stackPointer);
                break;
            case I64_EQ:
                i64_eq(frame, stackPointer);
                stackPointer--;
                break;
            case I64_NE:
                i64_ne(frame, stackPointer);
                stackPointer--;
                break;
            case I64_LT_S:
                i64_lt_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_LT_U:
                i64_lt_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_GT_S:
                i64_gt_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_GT_U:
                i64_gt_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_LE_S:
                i64_le_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_LE_U:
                i64_le_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_GE_S:
                i64_ge_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_GE_U:
                i64_ge_u(frame, stackPointer);
                stackPointer--;
                break;
            case F32_EQ:
                f32_eq(frame, stackPointer);
                stackPointer--;
                break;
            case F32_NE:
                f32_ne(frame, stackPointer);
                stackPointer--;
                break;
            case F32_LT:
                f32_lt(frame, stackPointer);
                stackPointer--;
                break;
            case F32_GT:
                f32_gt(frame, stackPointer);
                stackPointer--;
                break;
            case F32_LE:
                f32_le(frame, stackPointer);
                stackPointer--;
                break;
            case F32_GE:
                f32_ge(frame, stackPointer);
                stackPointer--;
                break;
            case F64_EQ:
                f64_eq(frame, stackPointer);
                stackPointer--;
                break;
            case F64_NE:
                f64_ne(frame, stackPointer);
                stackPointer--;
                break;
            case F64_LT:
                f64_lt(frame, stackPointer);
                stackPointer--;
                break;
            case F64_GT:
                f64_gt(frame, stackPointer);
                stackPointer--;
                break;
            case F64_LE:
                f64_le(frame, stackPointer);
                stackPointer--;
                break;
            case F64_GE:
                f64_ge(frame, stackPointer);
                stackPointer--;
                break;
            case I32_CLZ:
                i32_clz(frame, stackPointer);
                break;
            case I32_CTZ:
                i32_ctz(frame, stackPointer);
                break;
            case I32_POPCNT:
                i32_popcnt(frame, stackPointer);
                break;
            case I32_ADD:
                i32_add(frame, stackPointer);
                stackPointer--;
                break;
            case I32_SUB:
                i32_sub(frame, stackPointer);
                stackPointer--;
                break;
            case I32_MUL:
                i32_mul(frame, stackPointer);
                stackPointer--;
                break;
            case I32_DIV_S:
                i32_div_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_DIV_U:
                i32_div_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_REM_S:
                i32_rem_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_REM_U:
                i32_rem_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_AND:
                i32_and(frame, stackPointer);
                stackPointer--;
                break;
            case I32_OR:
                i32_or(frame, stackPointer);
                stackPointer--;
                break;
            case I32_XOR:
                i32_xor(frame, stackPointer);
                stackPointer--;
                break;
            case I32_SHL:
                i32_shl(frame, stackPointer);
                stackPointer--;
                break;
            case I32_SHR_S:
                i32_shr_s(frame, stackPointer);
                stackPointer--;
                break;
            case I32_SHR_U:
                i32_shr_u(frame, stackPointer);
                stackPointer--;
                break;
            case I32_ROTL:
                i32_rotl(frame, stackPointer);
                stackPointer--;
                break;
            case I32_ROTR:
                i32_rotr(frame, stackPointer);
                stackPointer--;
                break;
            case I64_CLZ:
                i64_clz(frame, stackPointer);
                break;
            case I64_CTZ:
                i64_ctz(frame, stackPointer);
                break;
            case I64_POPCNT:
                i64_popcnt(frame, stackPointer);
                break;
            case I64_ADD:
                i64_add(frame, stackPointer);
                stackPointer--;
                break;
            case I64_SUB:
                i64_sub(frame, stackPointer);
                stackPointer--;
                break;
            case I64_MUL:
                i64_mul(frame, stackPointer);
                stackPointer--;
                break;
            case I64_DIV_S:
                i64_div_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_DIV_U:
                i64_div_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_REM_S:
                i64_rem_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_REM_U:
                i64_rem_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_AND:
                i64_and(frame, stackPointer);
                stackPointer--;
                break;
            case I64_OR:
                i64_or(frame, stackPointer);
                stackPointer--;
                break;
            case I64_XOR:
                i64_xor(frame, stackPointer);
                stackPointer--;
                break;
            case I64_SHL:
                i64_shl(frame, stackPointer);
                stackPointer--;
                break;
            case I64_SHR_S:
                i64_shr_s(frame, stackPointer);
                stackPointer--;
                break;
            case I64_SHR_U:
                i64_shr_u(frame, stackPointer);
                stackPointer--;
                break;
            case I64_ROTL:
                i64_rotl(frame, stackPointer);
                stackPointer--;
                break;
            case I64_ROTR:
                i64_rotr(frame, stackPointer);
                stackPointer--;
                break;
            case F32_CONST:
                {
                    // region Load int value
                    float value = Float.intBitsToFloat(BinaryStreamParser.peek4(data, offset));
                    // endregion
                    offset += 4;
                    pushFloat(frame, stackPointer, value);
                    stackPointer++;
                    break;
                }
            case F32_ABS:
                f32_abs(frame, stackPointer);
                break;
            case F32_NEG:
                f32_neg(frame, stackPointer);
                break;
            case F32_CEIL:
                f32_ceil(frame, stackPointer);
                break;
            case F32_FLOOR:
                f32_floor(frame, stackPointer);
                break;
            case F32_TRUNC:
                f32_trunc(frame, stackPointer);
                break;
            case F32_NEAREST:
                f32_nearest(frame, stackPointer);
                break;
            case F32_SQRT:
                f32_sqrt(frame, stackPointer);
                break;
            case F32_ADD:
                f32_add(frame, stackPointer);
                stackPointer--;
                break;
            case F32_SUB:
                f32_sub(frame, stackPointer);
                stackPointer--;
                break;
            case F32_MUL:
                f32_mul(frame, stackPointer);
                stackPointer--;
                break;
            case F32_DIV:
                f32_div(frame, stackPointer);
                stackPointer--;
                break;
            case F32_MIN:
                f32_min(frame, stackPointer);
                stackPointer--;
                break;
            case F32_MAX:
                f32_max(frame, stackPointer);
                stackPointer--;
                break;
            case F32_COPYSIGN:
                f32_copysign(frame, stackPointer);
                stackPointer--;
                break;
            case F64_CONST:
                {
                    // region Load long value
                    double value = Double.longBitsToDouble(BinaryStreamParser.peek8(data, offset));
                    // endregion
                    offset += 8;
                    pushDouble(frame, stackPointer, value);
                    stackPointer++;
                    break;
                }
            case F64_ABS:
                f64_abs(frame, stackPointer);
                break;
            case F64_NEG:
                f64_neg(frame, stackPointer);
                break;
            case F64_CEIL:
                f64_ceil(frame, stackPointer);
                break;
            case F64_FLOOR:
                f64_floor(frame, stackPointer);
                break;
            case F64_TRUNC:
                f64_trunc(frame, stackPointer);
                break;
            case F64_NEAREST:
                f64_nearest(frame, stackPointer);
                break;
            case F64_SQRT:
                f64_sqrt(frame, stackPointer);
                break;
            case F64_ADD:
                f64_add(frame, stackPointer);
                stackPointer--;
                break;
            case F64_SUB:
                f64_sub(frame, stackPointer);
                stackPointer--;
                break;
            case F64_MUL:
                f64_mul(frame, stackPointer);
                stackPointer--;
                break;
            case F64_DIV:
                f64_div(frame, stackPointer);
                stackPointer--;
                break;
            case F64_MIN:
                f64_min(frame, stackPointer);
                stackPointer--;
                break;
            case F64_MAX:
                f64_max(frame, stackPointer);
                stackPointer--;
                break;
            case F64_COPYSIGN:
                f64_copysign(frame, stackPointer);
                stackPointer--;
                break;
            case I32_WRAP_I64:
                i32_wrap_i64(frame, stackPointer);
                break;
            case I32_TRUNC_F32_S:
                i32_trunc_f32_s(frame, stackPointer);
                break;
            case I32_TRUNC_F32_U:
                i32_trunc_f32_u(frame, stackPointer);
                break;
            case I32_TRUNC_F64_S:
                i32_trunc_f64_s(frame, stackPointer);
                break;
            case I32_TRUNC_F64_U:
                i32_trunc_f64_u(frame, stackPointer);
                break;
            case I64_EXTEND_I32_S:
                i64_extend_i32_s(frame, stackPointer);
                break;
            case I64_EXTEND_I32_U:
                i64_extend_i32_u(frame, stackPointer);
                break;
            case I64_TRUNC_F32_S:
                i64_trunc_f32_s(frame, stackPointer);
                break;
            case I64_TRUNC_F32_U:
                i64_trunc_f32_u(frame, stackPointer);
                break;
            case I64_TRUNC_F64_S:
                i64_trunc_f64_s(frame, stackPointer);
                break;
            case I64_TRUNC_F64_U:
                i64_trunc_f64_u(frame, stackPointer);
                break;
            case F32_CONVERT_I32_S:
                f32_convert_i32_s(frame, stackPointer);
                break;
            case F32_CONVERT_I32_U:
                f32_convert_i32_u(frame, stackPointer);
                break;
            case F32_CONVERT_I64_S:
                f32_convert_i64_s(frame, stackPointer);
                break;
            case F32_CONVERT_I64_U:
                f32_convert_i64_u(frame, stackPointer);
                break;
            case F32_DEMOTE_F64:
                f32_demote_f64(frame, stackPointer);
                break;
            case F64_CONVERT_I32_S:
                f64_convert_i32_s(frame, stackPointer);
                break;
            case F64_CONVERT_I32_U:
                f64_convert_i32_u(frame, stackPointer);
                break;
            case F64_CONVERT_I64_S:
                f64_convert_i64_s(frame, stackPointer);
                break;
            case F64_CONVERT_I64_U:
                f64_convert_i64_u(frame, stackPointer);
                break;
            case F64_PROMOTE_F32:
                f64_promote_f32(frame, stackPointer);
                break;
            case I32_REINTERPRET_F32:
                i32_reinterpret_f32(frame, stackPointer);
                break;
            case I64_REINTERPRET_F64:
                i64_reinterpret_f64(frame, stackPointer);
                break;
            case F32_REINTERPRET_I32:
                f32_reinterpret_i32(frame, stackPointer);
                break;
            case F64_REINTERPRET_I64:
                f64_reinterpret_i64(frame, stackPointer);
                break;
            case MISC:
                byte miscByteOpcode = BinaryStreamParser.rawPeek1(data, offset);
                int miscOpcode = miscByteOpcode & 0xFF;
                offset++;
                CompilerAsserts.partialEvaluationConstant(offset);
                switch(miscOpcode) {
                    case I32_TRUNC_SAT_F32_S:
                        i32_trunc_sat_f32_s(frame, stackPointer);
                        break;
                    case I32_TRUNC_SAT_F32_U:
                        i32_trunc_sat_f32_u(frame, stackPointer);
                        break;
                    case I32_TRUNC_SAT_F64_S:
                        i32_trunc_sat_f64_s(frame, stackPointer);
                        break;
                    case I32_TRUNC_SAT_F64_U:
                        i32_trunc_sat_f64_u(frame, stackPointer);
                        break;
                    case I64_TRUNC_SAT_F32_S:
                        i64_trunc_sat_f32_s(frame, stackPointer);
                        break;
                    case I64_TRUNC_SAT_F32_U:
                        i64_trunc_sat_f32_u(frame, stackPointer);
                        break;
                    case I64_TRUNC_SAT_F64_S:
                        i64_trunc_sat_f64_s(frame, stackPointer);
                        break;
                    case I64_TRUNC_SAT_F64_U:
                        i64_trunc_sat_f64_u(frame, stackPointer);
                        break;
                    default:
                        throw CompilerDirectives.shouldNotReachHere();
                }
                break;
            case I32_EXTEND8_S:
                i32_extend8_s(frame, stackPointer);
                break;
            case I32_EXTEND16_S:
                i32_extend16_s(frame, stackPointer);
                break;
            case I64_EXTEND8_S:
                i64_extend8_s(frame, stackPointer);
                break;
            case I64_EXTEND16_S:
                i64_extend16_s(frame, stackPointer);
                break;
            case I64_EXTEND32_S:
                i64_extend32_s(frame, stackPointer);
                break;
            default:
                throw CompilerDirectives.shouldNotReachHere();
        }
    }
    return -1;
}
Also used : LoopNode(com.oracle.truffle.api.nodes.LoopNode) CallTarget(com.oracle.truffle.api.CallTarget) WasmTable(org.graalvm.wasm.WasmTable) TruffleContext(com.oracle.truffle.api.TruffleContext) SymbolTable(org.graalvm.wasm.SymbolTable) WasmCodeEntry(org.graalvm.wasm.WasmCodeEntry) WasmFunction(org.graalvm.wasm.WasmFunction) WasmContext(org.graalvm.wasm.WasmContext) WasmFunctionInstance(org.graalvm.wasm.WasmFunctionInstance) WasmMemory(org.graalvm.wasm.memory.WasmMemory) BytecodeInterpreterSwitch(com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitch) ExplodeLoop(com.oracle.truffle.api.nodes.ExplodeLoop) BytecodeInterpreterSwitchBoundary(com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitchBoundary)

Aggregations

WasmContext (org.graalvm.wasm.WasmContext)8 WasmInstance (org.graalvm.wasm.WasmInstance)3 TruffleContext (com.oracle.truffle.api.TruffleContext)2 Value (org.graalvm.polyglot.Value)2 WasmFunctionInstance (org.graalvm.wasm.WasmFunctionInstance)2 WasmMemory (org.graalvm.wasm.memory.WasmMemory)2 CallTarget (com.oracle.truffle.api.CallTarget)1 BytecodeInterpreterSwitch (com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitch)1 BytecodeInterpreterSwitchBoundary (com.oracle.truffle.api.HostCompilerDirectives.BytecodeInterpreterSwitchBoundary)1 VirtualFrame (com.oracle.truffle.api.frame.VirtualFrame)1 ArityException (com.oracle.truffle.api.interop.ArityException)1 InteropLibrary (com.oracle.truffle.api.interop.InteropLibrary)1 TruffleObject (com.oracle.truffle.api.interop.TruffleObject)1 UnknownIdentifierException (com.oracle.truffle.api.interop.UnknownIdentifierException)1 UnsupportedMessageException (com.oracle.truffle.api.interop.UnsupportedMessageException)1 UnsupportedTypeException (com.oracle.truffle.api.interop.UnsupportedTypeException)1 ExplodeLoop (com.oracle.truffle.api.nodes.ExplodeLoop)1 LoopNode (com.oracle.truffle.api.nodes.LoopNode)1 RootNode (com.oracle.truffle.api.nodes.RootNode)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1