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);
}
}
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());
}
});
}
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);
}
}
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));
}
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;
}
Aggregations