diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java index 674f3108c456..0e6ceaffc76e 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -83,6 +83,7 @@ import org.graalvm.wasm.WasmInstance; import org.graalvm.wasm.WasmLanguage; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.test.options.WasmTestOptions; import org.graalvm.wasm.utils.WasmBinaryTools; import org.graalvm.wasm.utils.cases.WasmCase; @@ -235,7 +236,7 @@ private void runInContext(WasmCase testCase, Context context, List sourc final boolean reinitMemory = requiresZeroMemory || iterationNeedsStateCheck(i + 1); if (reinitMemory) { for (int j = 0; j < wasmContext.memories().count(); ++j) { - wasmContext.memories().memory(j).reset(); + WasmMemoryLibrary.getUncached().reset(wasmContext.memories().memory(j)); } for (int j = 0; j < wasmContext.tables().tableCount(); ++j) { wasmContext.tables().table(j).reset(); @@ -602,11 +603,12 @@ private static void assertContextEqual(ContextState expectedState, ContextState if (expectedMemory == null) { Assert.assertNull("Memory should be null", actualMemory); } else { + WasmMemoryLibrary memories = WasmMemoryLibrary.getUncached(); Assert.assertNotNull("Memory should not be null", actualMemory); - Assert.assertEquals("Mismatch in memory lengths", expectedMemory.byteSize(), actualMemory.byteSize()); - for (int ptr = 0; ptr < expectedMemory.byteSize(); ptr++) { - byte expectedByte = (byte) expectedMemory.load_i32_8s(null, ptr); - byte actualByte = (byte) actualMemory.load_i32_8s(null, ptr); + Assert.assertEquals("Mismatch in memory lengths", memories.byteSize(expectedMemory), memories.byteSize(actualMemory)); + for (int ptr = 0; ptr < memories.byteSize(expectedMemory); ptr++) { + byte expectedByte = (byte) memories.load_i32_8s(expectedMemory, null, ptr); + byte actualByte = (byte) memories.load_i32_8s(actualMemory, null, ptr); Assert.assertEquals("Memory mismatch at offset " + ptr + ",", expectedByte, actualByte); } } diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java index 14634f78c219..e7e24ec91039 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmJsApiSuite.java @@ -78,6 +78,7 @@ import org.graalvm.wasm.globals.DefaultWasmGlobal; import org.graalvm.wasm.globals.WasmGlobal; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.testutil.TestutilModule; import org.junit.Assert; import org.junit.Test; @@ -163,6 +164,7 @@ public void testInstantiateWithImportMemory() throws IOException { runMemoryTest(context -> { final WebAssembly wasm = new WebAssembly(context); final WasmMemory memory = WebAssembly.memAlloc(4, 8, false); + final WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); final Dictionary importObject = Dictionary.create(new Object[]{ "host", Dictionary.create(new Object[]{ "defaultMemory", memory @@ -171,9 +173,9 @@ public void testInstantiateWithImportMemory() throws IOException { final WasmInstance instance = moduleInstantiate(wasm, binaryWithMemoryImport, importObject); try { final Object initZero = WebAssembly.instanceExport(instance, "initZero"); - Assert.assertEquals("Must be zero initially.", 0, memory.load_i32(null, 0)); + Assert.assertEquals("Must be zero initially.", 0, memoryLib.load_i32(memory, null, 0)); InteropLibrary.getUncached(initZero).execute(initZero); - Assert.assertEquals("Must be 174 after initialization.", 174, memory.load_i32(null, 0)); + Assert.assertEquals("Must be 174 after initialization.", 174, memoryLib.load_i32(memory, null, 0)); } catch (InteropException e) { throw new RuntimeException(e); } @@ -187,8 +189,9 @@ public void testInstantiateWithExportMemory() throws IOException { WasmInstance instance = moduleInstantiate(wasm, binaryWithMemoryExport, null); try { final WasmMemory memory = (WasmMemory) WebAssembly.instanceExport(instance, "memory"); + final WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); final Object readZero = WebAssembly.instanceExport(instance, "readZero"); - memory.store_i32(null, 0, 174); + memoryLib.store_i32(memory, null, 0, 174); final Object result = InteropLibrary.getUncached(readZero).execute(readZero); Assert.assertEquals("Must be 174.", 174, InteropLibrary.getUncached(result).asInt(result)); } catch (InteropException e) { @@ -1432,11 +1435,14 @@ public void testMultiValueReferencePassThrough() throws IOException, Interrupted @Test public void testInitialMemorySizeOutOfBounds() throws IOException { runMemoryTest(context -> { - try { - WebAssembly.memAlloc(32768, 32770, false); - Assert.fail("Should have failed - initial memory size exceeds implementation limit"); - } catch (WasmJsApiException e) { - Assert.assertEquals("Range error expected", WasmJsApiException.Kind.RangeError, e.kind()); + // When not enforcing unsafe memory, implementation limits are lifted. + if (context.getContextOptions().useUnsafeMemory()) { + try { + WebAssembly.memAlloc(32768, 32770, false); + Assert.fail("Should have failed - initial memory size exceeds implementation limit"); + } catch (WasmJsApiException e) { + Assert.assertEquals("Range error expected", WasmJsApiException.Kind.RangeError, e.kind()); + } } }); } diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java index bb6ce1f2a577..70385adee8d9 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/WasmImplementationLimitationsSuite.java @@ -54,8 +54,8 @@ import org.junit.runners.Parameterized; import java.io.IOException; -import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import static org.graalvm.wasm.utils.WasmBinaryTools.compileWat; @@ -63,13 +63,10 @@ public class WasmImplementationLimitationsSuite { @Parameterized.Parameters(name = "{0}") public static Collection data() { - return Arrays.asList( + return Collections.singletonList( stringCase("Table instance - initial size out of bounds", "table instance size exceeds limit: 2147483648 should be <= 10000000", - "(table $table1 2147483648 funcref)", Failure.Type.TRAP), - stringCase("Memory instance - initial size out of bounds", - "memory instance size exceeds limit: 32768 should be <= 32767", - "(memory $memory1 32768)", Failure.Type.TRAP)); + "(table $table1 2147483648 funcref)", Failure.Type.TRAP)); } private final String expectedErrorMessage; diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java index 0e3d40a06041..3eae2a0f0b6d 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/bytecode/MultiInstantiationSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -66,6 +66,7 @@ import org.graalvm.wasm.exception.WasmJsApiException; import org.graalvm.wasm.globals.WasmGlobal; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.testutil.TestutilModule; import org.graalvm.wasm.utils.WasmBinaryTools; import org.junit.Assert; @@ -192,7 +193,8 @@ public void testImportsAndExports() throws IOException, InterruptedException { a.addMember("t", t); final WasmMemory m = WebAssembly.memAlloc(1, 1, false); - m.store_i32_8(null, 0, (byte) 5); + final WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + memoryLib.store_i32_8(m, null, 0, (byte) 5); a.addMember("m", m); final WasmGlobal g = wasm.globalAlloc(ValueType.i32, false, 4); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java index 2f09d86e75ca..2f9e171106d7 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/BinaryParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -423,8 +423,7 @@ private void readImportSection() { final int memoryIndex = module.memoryCount(); final boolean is64Bit = booleanMultiResult[0]; final boolean isShared = booleanMultiResult[1]; - final boolean useUnsafeMemory = wasmContext.getContextOptions().useUnsafeMemory(); - module.symbolTable().importMemory(moduleName, memberName, memoryIndex, longMultiResult[0], longMultiResult[1], is64Bit, isShared, multiMemory, useUnsafeMemory); + module.symbolTable().importMemory(moduleName, memberName, memoryIndex, longMultiResult[0], longMultiResult[1], is64Bit, isShared, multiMemory); break; } case ImportIdentifier.GLOBAL: { @@ -473,7 +472,8 @@ private void readMemorySection() { final boolean is64Bit = booleanMultiResult[0]; final boolean isShared = booleanMultiResult[1]; final boolean useUnsafeMemory = wasmContext.getContextOptions().useUnsafeMemory(); - module.symbolTable().allocateMemory(memoryIndex, longMultiResult[0], longMultiResult[1], is64Bit, isShared, multiMemory, useUnsafeMemory); + final boolean directByteBufferMemoryAccess = wasmContext.getContextOptions().directByteBufferMemoryAccess(); + module.symbolTable().allocateMemory(memoryIndex, longMultiResult[0], longMultiResult[1], is64Bit, isShared, multiMemory, useUnsafeMemory, directByteBufferMemoryAccess); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java index 8dcbb6b5285c..f69e490eee9f 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -73,6 +73,7 @@ import java.util.Set; import java.util.function.Function; +import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.Linker.ResolutionDag.CallsiteSym; import org.graalvm.wasm.Linker.ResolutionDag.CodeEntrySym; import org.graalvm.wasm.Linker.ResolutionDag.DataSym; @@ -99,7 +100,9 @@ import org.graalvm.wasm.globals.WasmGlobal; import org.graalvm.wasm.memory.NativeDataInstanceUtil; import org.graalvm.wasm.memory.WasmMemory; -import org.graalvm.wasm.nodes.WasmFunctionNode; +import org.graalvm.wasm.memory.WasmMemoryLibrary; +import org.graalvm.wasm.nodes.WasmCallStubNode; +import org.graalvm.wasm.nodes.WasmDirectCallNode; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; @@ -107,6 +110,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.TruffleContext; +import org.graalvm.wasm.nodes.WasmIndirectCallNode; public class Linker { public enum LinkState { @@ -468,13 +472,24 @@ void resolveFunctionExport(WasmModule module, int functionIndex, String exported resolutionDag.resolveLater(new ExportFunctionSym(module.name(), exportedFunctionName), dependencies, NO_RESOLVE_ACTION); } - void resolveCallsite(WasmInstance instance, WasmFunctionNode functionNode, int controlTableOffset, int bytecodeOffset, WasmFunction function) { - final Runnable resolveAction = () -> functionNode.resolveCallNode(instance, controlTableOffset, bytecodeOffset); + public void resolveCallNode(Node[] callNodes, WasmInstance instance, int callNodeIndex, int bytecodeOffset) { + Node unresolvedCallNode = callNodes[callNodeIndex]; + if (unresolvedCallNode instanceof WasmCallStubNode) { + final WasmFunction function = ((WasmCallStubNode) unresolvedCallNode).function(); + final CallTarget target = instance.target(function.index()); + callNodes[callNodeIndex] = WasmDirectCallNode.create(target, bytecodeOffset); + } else { + assert unresolvedCallNode instanceof WasmIndirectCallNode : unresolvedCallNode; + } + } + + public void resolveCallsite(WasmInstance instance, Node[] callNodes, int instructionOffset, int controlTableOffset, int bytecodeOffset, WasmFunction function) { + final Runnable resolveAction = () -> resolveCallNode(callNodes, instance, controlTableOffset, bytecodeOffset); final Sym[] dependencies = new Sym[]{ function.isImported() ? new ImportFunctionSym(instance.name(), function.importDescriptor(), function.index()) : new CodeEntrySym(instance.name(), function.index())}; - resolutionDag.resolveLater(new CallsiteSym(instance.name(), functionNode.startOffset(), controlTableOffset), dependencies, resolveAction); + resolutionDag.resolveLater(new CallsiteSym(instance.name(), instructionOffset, controlTableOffset), dependencies, resolveAction); } void resolveCodeEntry(WasmModule module, int functionIndex) { @@ -750,10 +765,11 @@ void resolveDataSegment(WasmContext context, WasmInstance instance, int dataSegm baseAddress = offsetAddress; } - Assert.assertUnsignedLongLessOrEqual(baseAddress, memory.byteSize(), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); - Assert.assertUnsignedLongLessOrEqual(baseAddress + byteLength, memory.byteSize(), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + Assert.assertUnsignedLongLessOrEqual(baseAddress, memoryLib.byteSize(memory), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); + Assert.assertUnsignedLongLessOrEqual(baseAddress + byteLength, memoryLib.byteSize(memory), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); final byte[] bytecode = instance.module().bytecode(); - memory.initialize(bytecode, bytecodeOffset, baseAddress, byteLength); + memoryLib.initialize(memory, bytecode, bytecodeOffset, baseAddress, byteLength); instance.setDataInstance(dataSegmentId, droppedDataInstanceOffset); }; final ArrayList dependencies = new ArrayList<>(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/MemoryRegistry.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/MemoryRegistry.java index a7c0102ba148..ac56b57c5911 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/MemoryRegistry.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/MemoryRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -42,6 +42,7 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; public class MemoryRegistry { private static final int INITIAL_MEMORIES_SIZE = 4; @@ -86,7 +87,7 @@ public WasmMemory memory(int index) { public MemoryRegistry duplicate() { final MemoryRegistry other = new MemoryRegistry(); for (int i = 0; i < numMemories; i++) { - final WasmMemory memory = memory(i).duplicate(); + final WasmMemory memory = WasmMemoryLibrary.getUncached().duplicate(memory(i)); other.register(memory); } return other; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java index a9258baaed9a..99739ed06807 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/SymbolTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -50,7 +50,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; @@ -201,14 +200,11 @@ public static class MemoryInfo { */ public final boolean shared; - public final Class memoryImpl; - - public MemoryInfo(long initialSize, long maximumSize, boolean indexType64, boolean shared, Class memoryImpl) { + public MemoryInfo(long initialSize, long maximumSize, boolean indexType64, boolean shared) { this.initialSize = initialSize; this.maximumSize = maximumSize; this.indexType64 = indexType64; this.shared = shared; - this.memoryImpl = Objects.requireNonNull(memoryImpl); } } @@ -1009,22 +1005,18 @@ private void ensureMemoryCapacity(int index) { } } - private long maxAllowedSize(long declaredMaxSize, boolean indexType64) { - return minUnsigned(declaredMaxSize, module().limits().memoryInstanceSizeLimit(indexType64)); - } - - public void allocateMemory(int index, long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared, boolean multiMemory, boolean useUnsafeMemory) { + public void allocateMemory(int index, long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared, boolean multiMemory, boolean useUnsafeMemory, + boolean directByteBufferMemoryAccess) { checkNotParsed(); - final long maxAllowedSize = maxAllowedSize(declaredMaxSize, indexType64); - addMemory(index, declaredMinSize, declaredMaxSize, maxAllowedSize, indexType64, shared, multiMemory, useUnsafeMemory); + addMemory(index, declaredMinSize, declaredMaxSize, indexType64, shared, multiMemory); module().addLinkAction((context, instance, imports) -> { module().limits().checkMemoryInstanceSize(declaredMinSize, indexType64); final WasmMemory wasmMemory; if (context.getContextOptions().memoryOverheadMode()) { // Initialize an empty memory when in memory overhead mode. - wasmMemory = WasmMemoryFactory.createMemory(0, 0, 0, false, false, useUnsafeMemory); + wasmMemory = WasmMemoryFactory.createMemory(0, 0, false, false, useUnsafeMemory, directByteBufferMemoryAccess); } else { - wasmMemory = WasmMemoryFactory.createMemory(declaredMinSize, declaredMaxSize, maxAllowedSize, indexType64, shared, useUnsafeMemory); + wasmMemory = WasmMemoryFactory.createMemory(declaredMinSize, declaredMaxSize, indexType64, shared, useUnsafeMemory, directByteBufferMemoryAccess); } final int memoryAddress = context.memories().register(wasmMemory); final WasmMemory allocatedMemory = context.memories().memory(memoryAddress); @@ -1032,9 +1024,9 @@ public void allocateMemory(int index, long declaredMinSize, long declaredMaxSize }); } - public void importMemory(String moduleName, String memoryName, int index, long initSize, long maxSize, boolean typeIndex64, boolean shared, boolean multiMemory, boolean useUnsafeMemory) { + public void importMemory(String moduleName, String memoryName, int index, long initSize, long maxSize, boolean typeIndex64, boolean shared, boolean multiMemory) { checkNotParsed(); - addMemory(index, initSize, maxSize, maxAllowedSize(maxSize, typeIndex64), typeIndex64, shared, multiMemory, useUnsafeMemory); + addMemory(index, initSize, maxSize, typeIndex64, shared, multiMemory); final ImportDescriptor importedMemory = new ImportDescriptor(moduleName, memoryName, ImportIdentifier.MEMORY, index, numImportedSymbols()); importedMemories.put(index, importedMemory); importSymbol(importedMemory); @@ -1043,14 +1035,13 @@ public void importMemory(String moduleName, String memoryName, int index, long i }); } - void addMemory(int index, long minSize, long maxSize, long maxAllowedSize, boolean indexType64, boolean shared, boolean multiMemory, boolean useUnsafeMemory) { + void addMemory(int index, long minSize, long maxSize, boolean indexType64, boolean shared, boolean multiMemory) { if (!multiMemory) { assertTrue(importedMemories.size() == 0, "A memory has already been imported in the module.", Failure.MULTIPLE_MEMORIES); assertTrue(memoryCount == 0, "A memory has already been declared in the module.", Failure.MULTIPLE_MEMORIES); } ensureMemoryCapacity(index); - var memoryImpl = WasmMemoryFactory.getMemoryImplementation(maxAllowedSize, useUnsafeMemory); - final MemoryInfo memory = new MemoryInfo(minSize, maxSize, indexType64, shared, memoryImpl); + final MemoryInfo memory = new MemoryInfo(minSize, maxSize, indexType64, shared); memories[index] = memory; memoryCount++; } @@ -1112,16 +1103,6 @@ public boolean memoryIsShared(int index) { return memory.shared; } - public final WasmMemory castMemory(WasmMemory memoryInstance, int index) { - final MemoryInfo memory = memories[index]; - return CompilerDirectives.castExact(memoryInstance, memory.memoryImpl); - } - - public final WasmMemory memory(WasmInstance moduleInstance, int index) { - final WasmMemory memoryInstance = moduleInstance.memory(index); - return castMemory(memoryInstance, index); - } - void allocateCustomSection(String name, int offset, int length) { customSections.add(new WasmCustomSection(name, offset, length)); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java index 87df2fb729e5..10c2303eac87 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -61,6 +61,7 @@ public class WasmContextOptions { @CompilationFinal private boolean memoryOverheadMode; @CompilationFinal private boolean constantRandomGet; + @CompilationFinal private boolean directByteBufferMemoryAccess; @CompilationFinal private String debugCompDirectory; private final OptionValues optionValues; @@ -88,6 +89,10 @@ private void setOptionValues() { this.simd = readBooleanOption(WasmOptions.SIMD); this.memoryOverheadMode = readBooleanOption(WasmOptions.MemoryOverheadMode); this.constantRandomGet = readBooleanOption(WasmOptions.WasiConstantRandomGet); + // Temporary: Default DirectByteBufferMemoryAccess to true when UseUnsafeMemory is set to + // true. After GraalNode.js starts setting DirectByteBufferMemoryAccess, we can default + // DirectByteBufferMemoryAccess to false. + this.directByteBufferMemoryAccess = WasmOptions.DirectByteBufferMemoryAccess.hasBeenSet(optionValues) ? readBooleanOption(WasmOptions.DirectByteBufferMemoryAccess) : unsafeMemory; this.debugCompDirectory = readStringOption(WasmOptions.DebugCompDirectory); } @@ -95,6 +100,9 @@ private void checkOptionDependencies() { if (memory64 && !unsafeMemory) { failDependencyCheck("Memory64", "UseUnsafeMemory"); } + if (directByteBufferMemoryAccess && !unsafeMemory) { + failDependencyCheck("DirectByteBufferMemoryAccess", "UseUnsafeMemory"); + } } private boolean readBooleanOption(OptionKey key) { @@ -157,6 +165,10 @@ public boolean constantRandomGet() { return constantRandomGet; } + public boolean directByteBufferMemoryAccess() { + return directByteBufferMemoryAccess; + } + public String debugCompDirectory() { return debugCompDirectory; } @@ -175,6 +187,7 @@ public int hashCode() { hash = 53 * hash + (this.simd ? 1 : 0); hash = 53 * hash + (this.memoryOverheadMode ? 1 : 0); hash = 53 * hash + (this.constantRandomGet ? 1 : 0); + hash = 53 * hash + (this.directByteBufferMemoryAccess ? 1 : 0); hash = 53 * hash + (this.debugCompDirectory.hashCode()); return hash; } @@ -227,6 +240,9 @@ public boolean equals(Object obj) { if (this.constantRandomGet != other.constantRandomGet) { return false; } + if (this.directByteBufferMemoryAccess != other.directByteBufferMemoryAccess) { + return false; + } if (!this.debugCompDirectory.equals(other.debugCompDirectory)) { return false; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java index 361155693484..002628b73ea5 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmInstantiator.java @@ -53,11 +53,10 @@ import org.graalvm.wasm.memory.WasmMemory; import org.graalvm.wasm.memory.WasmMemoryFactory; import org.graalvm.wasm.nodes.WasmCallStubNode; -import org.graalvm.wasm.nodes.WasmFunctionNode; +import org.graalvm.wasm.nodes.WasmFixedMemoryImplFunctionNode; +import org.graalvm.wasm.nodes.WasmFunctionRootNode; import org.graalvm.wasm.nodes.WasmIndirectCallNode; -import org.graalvm.wasm.nodes.WasmInstrumentableFunctionNode; -import org.graalvm.wasm.nodes.WasmMemoryOverheadModeRootNode; -import org.graalvm.wasm.nodes.WasmRootNode; +import org.graalvm.wasm.nodes.WasmMemoryOverheadModeFunctionRootNode; import org.graalvm.wasm.parser.ir.CallNode; import org.graalvm.wasm.parser.ir.CodeEntry; @@ -194,10 +193,9 @@ static List recreateLinkActions(WasmModule module) { } else { linkActions.add((context, instance, imports) -> { final ModuleLimits limits = instance.module().limits(); - final long maxAllowedSize = WasmMath.minUnsigned(memoryMaxSize, limits.memoryInstanceSizeLimit()); limits.checkMemoryInstanceSize(memoryMinSize, memoryIndexType64); - final WasmMemory wasmMemory = WasmMemoryFactory.createMemory(memoryMinSize, memoryMaxSize, maxAllowedSize, memoryIndexType64, memoryShared, - context.getContextOptions().useUnsafeMemory()); + final WasmMemory wasmMemory = WasmMemoryFactory.createMemory(memoryMinSize, memoryMaxSize, memoryIndexType64, memoryShared, + context.getContextOptions().useUnsafeMemory(), context.getContextOptions().directByteBufferMemoryAccess()); final int address = context.memories().register(wasmMemory); final WasmMemory allocatedMemory = context.memories().memory(address); instance.setMemory(memoryIndex, allocatedMemory); @@ -457,12 +455,13 @@ private CallTarget instantiateCodeEntry(WasmContext context, WasmModule module, } final WasmCodeEntry wasmCodeEntry = new WasmCodeEntry(function, module.bytecode(), codeEntry.localTypes(), codeEntry.resultTypes(), codeEntry.usesMemoryZero()); final FrameDescriptor frameDescriptor = createFrameDescriptor(codeEntry.localTypes(), codeEntry.maxStackSize()); - final WasmInstrumentableFunctionNode functionNode = instantiateFunctionNode(module, instance, wasmCodeEntry, codeEntry); - final WasmRootNode rootNode; + final Node[] callNodes = setupCallNodes(module, instance, codeEntry); + final WasmFixedMemoryImplFunctionNode functionNode = WasmFixedMemoryImplFunctionNode.create(module, wasmCodeEntry, codeEntry.bytecodeStartOffset(), codeEntry.bytecodeEndOffset(), callNodes); + final WasmFunctionRootNode rootNode; if (context.getContextOptions().memoryOverheadMode()) { - rootNode = new WasmMemoryOverheadModeRootNode(language, frameDescriptor, functionNode); + rootNode = new WasmMemoryOverheadModeFunctionRootNode(language, frameDescriptor, module, functionNode, wasmCodeEntry); } else { - rootNode = new WasmRootNode(language, frameDescriptor, functionNode); + rootNode = new WasmFunctionRootNode(language, frameDescriptor, module, functionNode, wasmCodeEntry); } var callTarget = rootNode.getCallTarget(); if (context.language().isMultiContext()) { @@ -473,8 +472,7 @@ private CallTarget instantiateCodeEntry(WasmContext context, WasmModule module, return callTarget; } - private static WasmInstrumentableFunctionNode instantiateFunctionNode(WasmModule module, WasmInstance instance, WasmCodeEntry codeEntry, CodeEntry entry) { - final WasmFunctionNode currentFunction = new WasmFunctionNode(module, codeEntry, entry.bytecodeStartOffset(), entry.bytecodeEndOffset()); + private static Node[] setupCallNodes(WasmModule module, WasmInstance instance, CodeEntry entry) { List childNodeList = entry.callNodes(); Node[] callNodes = new Node[childNodeList.size()]; int childIndex = 0; @@ -499,13 +497,11 @@ private static WasmInstrumentableFunctionNode instantiateFunctionNode(WasmModule } final int stubIndex = childIndex; instance.addLinkAction((ctx, inst, imports) -> { - ctx.linker().resolveCallsite(inst, currentFunction, stubIndex, bytecodeIndex, resolvedFunction); + ctx.linker().resolveCallsite(inst, callNodes, entry.bytecodeStartOffset(), stubIndex, bytecodeIndex, resolvedFunction); }); } callNodes[childIndex++] = child; } - currentFunction.initializeCallNodes(callNodes); - final int sourceCodeLocation = module.functionSourceCodeStartOffset(codeEntry.functionIndex()); - return new WasmInstrumentableFunctionNode(module, codeEntry, currentFunction, sourceCodeLocation); + return callNodes; } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java index 0b7e846df38c..a04c23f87913 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmLanguage.java @@ -51,6 +51,7 @@ import org.graalvm.wasm.api.WebAssembly; import org.graalvm.wasm.exception.WasmJsApiException; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.BuiltinModule; import com.oracle.truffle.api.CallTarget; @@ -204,7 +205,7 @@ protected void finalizeContext(WasmContext context) { super.finalizeContext(context); for (int i = 0; i < context.memories().count(); ++i) { final WasmMemory memory = context.memories().memory(i); - memory.close(); + WasmMemoryLibrary.getUncached().close(memory); } try { context.fdManager().close(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java index 3ac8b74aefcb..44e97521344d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java @@ -115,6 +115,9 @@ public enum ConstantsStorePolicy { @Option(help = "Make WASI random_get always return the same random numbers. For testing purpose only.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // public static final OptionKey WasiConstantRandomGet = new OptionKey<>(false); + @Option(help = "Allows the embedder to access memories as direct byte buffers.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // + public static final OptionKey DirectByteBufferMemoryAccess = new OptionKey<>(false); + @Option(help = "Test dir used for testing the debugger.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "") // public static final OptionKey DebugCompDirectory = new OptionKey<>(""); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteHostFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteHostFunctionNode.java index 93edd235df76..9eb4bcafcd79 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteHostFunctionNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/ExecuteHostFunctionNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,6 +40,7 @@ */ package org.graalvm.wasm.api; +import com.oracle.truffle.api.nodes.RootNode; import org.graalvm.wasm.WasmArguments; import org.graalvm.wasm.WasmConstant; import org.graalvm.wasm.WasmContext; @@ -51,7 +52,6 @@ import org.graalvm.wasm.WasmType; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; -import org.graalvm.wasm.predefined.WasmBuiltinRootNode; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; @@ -69,7 +69,8 @@ /** * Wrapper call target for executing imported host functions in the parent context. */ -public final class ExecuteHostFunctionNode extends WasmBuiltinRootNode { +public final class ExecuteHostFunctionNode extends RootNode { + private final WasmModule module; private final int functionTypeIndex; private final int functionIndex; private final BranchProfile errorBranch = BranchProfile.create(); @@ -78,7 +79,8 @@ public final class ExecuteHostFunctionNode extends WasmBuiltinRootNode { @Child private InteropLibrary resultInterop; public ExecuteHostFunctionNode(WasmLanguage language, WasmModule module, WasmFunction fn) { - super(language, module); + super(language); + this.module = module; this.functionTypeIndex = fn.typeIndex(); this.functionIndex = fn.index(); this.functionInterop = InteropLibrary.getFactory().createDispatched(5); @@ -101,12 +103,12 @@ public Object execute(VirtualFrame frame) { Object executable = functionInstance.getImportedFunction(); result = functionInterop.execute(executable, arguments); - int resultCount = module().symbolTable().functionTypeResultCount(functionTypeIndex); + int resultCount = module.symbolTable().functionTypeResultCount(functionTypeIndex); CompilerAsserts.partialEvaluationConstant(resultCount); if (resultCount == 0) { return WasmConstant.VOID; } else if (resultCount == 1) { - byte resultType = module().symbolTable().functionTypeResultTypeAt(functionTypeIndex, 0); + byte resultType = module.symbolTable().functionTypeResultTypeAt(functionTypeIndex, 0); return convertResult(result, resultType); } else { pushMultiValueResult(result, resultCount); @@ -155,7 +157,7 @@ private void pushMultiValueResult(Object result, int resultCount) { final long[] primitiveMultiValueStack = multiValueStack.primitiveStack(); final Object[] objectMultiValueStack = multiValueStack.objectStack(); for (int i = 0; i < resultCount; i++) { - byte resultType = module().symbolTable().functionTypeResultTypeAt(functionTypeIndex, i); + byte resultType = module.symbolTable().functionTypeResultTypeAt(functionTypeIndex, i); CompilerAsserts.partialEvaluationConstant(resultType); Object value = arrayInterop.readArrayElement(result, i); switch (resultType) { @@ -229,8 +231,19 @@ private static String getMessage(InteropException e) { return e.getMessage(); } + // TODO: Do we need the 3 overrides below? @Override - public String builtinNodeName() { - return "execute"; + public String getName() { + return "wasm-function:execute"; + } + + @Override + public String toString() { + return getName(); + } + + @Override + protected boolean isInstrumentable() { + return false; } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java index e5b07bd2fca0..74f8522b41c0 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/JsConstants.java @@ -63,7 +63,7 @@ private JsConstants() { private static final int MULTI_VALUE_RESULT_COUNT_LIMIT = 1000; private static final int LOCAL_COUNT_LIMIT = 50000; private static final int TABLE_SIZE_LIMIT = 10000000; - private static final int MEMORY_SIZE_LIMIT = 32767; + private static final int MEMORY_SIZE_LIMIT = 65536; public static final ModuleLimits JS_LIMITS = new ModuleLimits( MODULE_SIZE_LIMIT, diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java index 2c36798d2216..92a97656948b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/api/WebAssembly.java @@ -61,7 +61,6 @@ import org.graalvm.wasm.WasmFunctionInstance; import org.graalvm.wasm.WasmInstance; import org.graalvm.wasm.WasmLanguage; -import org.graalvm.wasm.WasmMath; import org.graalvm.wasm.WasmModule; import org.graalvm.wasm.WasmTable; import org.graalvm.wasm.WasmType; @@ -84,6 +83,7 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; +import org.graalvm.wasm.memory.WasmMemoryLibrary; public class WebAssembly extends Dictionary { private final WasmContext currentContext; @@ -540,7 +540,7 @@ public WasmTable tableAlloc(int initial, int maximum, TableKind elemKind, Object if (!refTypes && elemKind == TableKind.externref) { throw new WasmJsApiException(WasmJsApiException.Kind.TypeError, "Element type must be anyfunc. Enable reference types to support externref"); } - final int maxAllowedSize = WasmMath.minUnsigned(maximum, JS_LIMITS.tableInstanceSizeLimit()); + final int maxAllowedSize = minUnsigned(maximum, JS_LIMITS.tableInstanceSizeLimit()); return new WasmTable(initial, maximum, maxAllowedSize, elemKind.byteValue(), initialValue); } @@ -714,14 +714,15 @@ private static Object memAlloc(Object[] args) { } public static WasmMemory memAlloc(int initial, int maximum, boolean shared) { + final WasmContext context = WasmContext.get(null); + boolean useUnsafeMemory = context.getContextOptions().useUnsafeMemory(); + boolean directByteBufferMemoryAccess = context.getContextOptions().directByteBufferMemoryAccess(); if (compareUnsigned(initial, maximum) > 0) { throw new WasmJsApiException(WasmJsApiException.Kind.RangeError, "Min memory size exceeds max memory size"); - } else if (Long.compareUnsigned(initial, JS_LIMITS.memoryInstanceSizeLimit()) > 0) { + } else if (Long.compareUnsigned(initial, WasmMemoryFactory.getMaximumAllowedSize(shared, useUnsafeMemory, directByteBufferMemoryAccess)) > 0) { throw new WasmJsApiException(WasmJsApiException.Kind.RangeError, "Min memory size exceeds implementation limit"); } - final long maxAllowedSize = minUnsigned(maximum, JS_LIMITS.memoryInstanceSizeLimit()); - final WasmContext context = WasmContext.get(null); - return WasmMemoryFactory.createMemory(initial, maximum, maxAllowedSize, false, shared, context.getContextOptions().useUnsafeMemory()); + return WasmMemoryFactory.createMemory(initial, maximum, false, shared, useUnsafeMemory, directByteBufferMemoryAccess); } private static Object memGrow(Object[] args) { @@ -738,9 +739,11 @@ private static Object memGrow(Object[] args) { } public static long memGrow(WasmMemory memory, int delta) { - final long previousSize = memory.grow(delta); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + final long previousSize = memoryLib.grow(memory, delta); if (previousSize == -1) { - throw new WasmJsApiException(WasmJsApiException.Kind.RangeError, "Cannot grow memory above max limit"); + throw new WasmJsApiException(WasmJsApiException.Kind.RangeError, + Math.addExact(memoryLib.size(memory), delta) <= memory.declaredMaxSize() ? "Cannot grow memory above implementation limit" : "Cannot grow memory above max limit"); } return previousSize; } @@ -865,7 +868,7 @@ private static Object memAsByteBuffer(Object[] args) { checkArgumentCount(args, 1); if (args[0] instanceof WasmMemory) { WasmMemory memory = (WasmMemory) args[0]; - ByteBuffer buffer = memory.asByteBuffer(); + ByteBuffer buffer = WasmMemoryLibrary.getUncached().asByteBuffer(memory); if (buffer != null) { return WasmContext.get(null).environment().asGuestValue(buffer); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Sizes.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Sizes.java index f7b62f2ca3d3..7f24aa1bfe09 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Sizes.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/constants/Sizes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -48,7 +48,7 @@ public final class Sizes { public static final int MEMORY_PAGE_SIZE = 65536; public static final int MAX_TABLE_INSTANCE_SIZE = Integer.MAX_VALUE; - public static final int MAX_MEMORY_INSTANCE_SIZE = Integer.MAX_VALUE / MEMORY_PAGE_SIZE; + public static final int MAX_MEMORY_INSTANCE_SIZE = MAX_MEMORY_DECLARATION_SIZE; // 64 TB public static final long MAX_MEMORY_64_INSTANCE_BYTE_SIZE = 64_000_000_000_000L; diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/exception/Failure.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/exception/Failure.java index e87bb376c26f..154162c96e95 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/exception/Failure.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/exception/Failure.java @@ -148,6 +148,7 @@ public enum Failure { MEMORY_OVERHEAD_MODE(Type.TRAP, "functions cannot be executed with memory overhead mode enabled"), SHARED_MEMORY_WITHOUT_UNSAFE(Type.TRAP, "shared memories are not supported without Unsafe"), + DIRECT_BYTE_BUFFER_WITHOUT_UNSAFE(Type.TRAP, "direct ByteBuffer memory access is not supported without Unsafe"), CALL_STACK_EXHAUSTED(Type.EXHAUSTION, "call stack exhausted"), MEMORY_ALLOCATION_FAILED(Type.EXHAUSTION, "could not allocate memory"), diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java index 950b3278bb4d..fb61bf66d699 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/ByteArrayWasmMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,16 +41,17 @@ package org.graalvm.wasm.memory; import static java.lang.Long.compareUnsigned; -import static java.lang.StrictMath.addExact; -import static java.lang.StrictMath.multiplyExact; +import static java.lang.Math.addExact; +import static java.lang.Math.multiplyExact; import static org.graalvm.wasm.constants.Sizes.MEMORY_PAGE_SIZE; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.ByteBuffer; import java.util.Arrays; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; import org.graalvm.wasm.api.Vector128; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; @@ -60,47 +61,53 @@ import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; +@ExportLibrary(WasmMemoryLibrary.class) final class ByteArrayWasmMemory extends WasmMemory { private byte[] dynamicBuffer; + public static final long MAX_ALLOWED_SIZE = Integer.MAX_VALUE / MEMORY_PAGE_SIZE; + + @TruffleBoundary private ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64, boolean shared) { super(declaredMinSize, declaredMaxSize, initialSize, maxAllowedSize, indexType64, shared); this.dynamicBuffer = allocateStatic(initialSize * MEMORY_PAGE_SIZE); } - ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, long maxAllowedSize, boolean indexType64, boolean shared) { - this(declaredMinSize, declaredMaxSize, declaredMinSize, maxAllowedSize, indexType64, shared); + @TruffleBoundary + ByteArrayWasmMemory(long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared) { + this(declaredMinSize, declaredMaxSize, declaredMinSize, Math.min(declaredMaxSize, MAX_ALLOWED_SIZE), indexType64, shared); } private byte[] buffer() { return dynamicBuffer; } - @Override + @ExportMessage public long size() { return byteSize() / MEMORY_PAGE_SIZE; } - @Override + @ExportMessage public long byteSize() { return buffer().length; } - @Override + @ExportMessage @TruffleBoundary public synchronized long grow(long extraPageSize) { long previousSize = size(); if (extraPageSize == 0) { invokeGrowCallback(); return previousSize; - } else if (compareUnsigned(extraPageSize, maxAllowedSize) <= 0 && compareUnsigned(size() + extraPageSize, maxAllowedSize) <= 0) { - // Condition above and limit on maxPageSize (see ModuleLimits#MAX_MEMORY_SIZE) - // ensure computation of targetByteSize does not overflow. - final long targetByteSize = multiplyExact(addExact(size(), extraPageSize), MEMORY_PAGE_SIZE); + } else if (compareUnsigned(extraPageSize, maxAllowedSize()) <= 0 && compareUnsigned(previousSize + extraPageSize, maxAllowedSize()) <= 0) { + // Condition above and limit on maxAllowedSize (see + // ByteArrayWasmMemory#MAX_ALLOWED_SIZE) ensure computation of targetByteSize does not + // overflow. + final long targetByteSize = multiplyExact(addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE); final byte[] currentBuffer = buffer(); allocate(targetByteSize); System.arraycopy(currentBuffer, 0, buffer(), 0, currentBuffer.length); - currentMinSize = size() + extraPageSize; + currentMinSize = previousSize + extraPageSize; invokeGrowCallback(); return previousSize; } else { @@ -108,14 +115,15 @@ public synchronized long grow(long extraPageSize) { } } - @Override + @ExportMessage @TruffleBoundary public void reset() { allocate(declaredMinSize * MEMORY_PAGE_SIZE); currentMinSize = declaredMinSize; } - @Override + // Checkstyle: stop + @ExportMessage public int load_i32(Node node, long address) { try { return ByteArraySupport.littleEndian().getInt(buffer(), address); @@ -124,7 +132,7 @@ public int load_i32(Node node, long address) { } } - @Override + @ExportMessage public long load_i64(Node node, long address) { try { return ByteArraySupport.littleEndian().getLong(buffer(), address); @@ -133,7 +141,7 @@ public long load_i64(Node node, long address) { } } - @Override + @ExportMessage public float load_f32(Node node, long address) { try { return ByteArraySupport.littleEndian().getFloat(buffer(), address); @@ -142,7 +150,7 @@ public float load_f32(Node node, long address) { } } - @Override + @ExportMessage public double load_f64(Node node, long address) { try { return ByteArraySupport.littleEndian().getDouble(buffer(), address); @@ -151,7 +159,7 @@ public double load_f64(Node node, long address) { } } - @Override + @ExportMessage public int load_i32_8s(Node node, long address) { try { return ByteArraySupport.littleEndian().getByte(buffer(), address); @@ -160,7 +168,7 @@ public int load_i32_8s(Node node, long address) { } } - @Override + @ExportMessage public int load_i32_8u(Node node, long address) { try { return 0x0000_00ff & ByteArraySupport.littleEndian().getByte(buffer(), address); @@ -169,7 +177,7 @@ public int load_i32_8u(Node node, long address) { } } - @Override + @ExportMessage public int load_i32_16s(Node node, long address) { try { return ByteArraySupport.littleEndian().getShort(buffer(), address); @@ -178,7 +186,7 @@ public int load_i32_16s(Node node, long address) { } } - @Override + @ExportMessage public int load_i32_16u(Node node, long address) { try { return 0x0000_ffff & ByteArraySupport.littleEndian().getShort(buffer(), address); @@ -187,7 +195,7 @@ public int load_i32_16u(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_8s(Node node, long address) { try { return ByteArraySupport.littleEndian().getByte(buffer(), address); @@ -196,7 +204,7 @@ public long load_i64_8s(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_8u(Node node, long address) { try { return 0x0000_0000_0000_00ffL & ByteArraySupport.littleEndian().getByte(buffer(), address); @@ -205,7 +213,7 @@ public long load_i64_8u(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_16s(Node node, long address) { try { return ByteArraySupport.littleEndian().getShort(buffer(), address); @@ -214,7 +222,7 @@ public long load_i64_16s(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_16u(Node node, long address) { try { return 0x0000_0000_0000_ffffL & ByteArraySupport.littleEndian().getShort(buffer(), address); @@ -223,7 +231,7 @@ public long load_i64_16u(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_32s(Node node, long address) { try { return ByteArraySupport.littleEndian().getInt(buffer(), address); @@ -232,7 +240,7 @@ public long load_i64_32s(Node node, long address) { } } - @Override + @ExportMessage public long load_i64_32u(Node node, long address) { try { return 0x0000_0000_ffff_ffffL & ByteArraySupport.littleEndian().getInt(buffer(), address); @@ -241,7 +249,7 @@ public long load_i64_32u(Node node, long address) { } } - @Override + @ExportMessage public Vector128 load_i128(Node node, long address) { if (ByteArraySupport.littleEndian().inBounds(buffer(), address, Vector128.BYTES)) { return new Vector128(Arrays.copyOfRange(buffer(), (int) address, (int) address + Vector128.BYTES)); @@ -250,7 +258,7 @@ public Vector128 load_i128(Node node, long address) { } } - @Override + @ExportMessage public void store_i32(Node node, long address, int value) { try { ByteArraySupport.littleEndian().putInt(buffer(), address, value); @@ -259,7 +267,7 @@ public void store_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public void store_i64(Node node, long address, long value) { try { ByteArraySupport.littleEndian().putLong(buffer(), address, value); @@ -269,7 +277,7 @@ public void store_i64(Node node, long address, long value) { } - @Override + @ExportMessage public void store_f32(Node node, long address, float value) { try { ByteArraySupport.littleEndian().putFloat(buffer(), address, value); @@ -278,7 +286,7 @@ public void store_f32(Node node, long address, float value) { } } - @Override + @ExportMessage public void store_f64(Node node, long address, double value) { try { ByteArraySupport.littleEndian().putDouble(buffer(), address, value); @@ -287,7 +295,7 @@ public void store_f64(Node node, long address, double value) { } } - @Override + @ExportMessage public void store_i32_8(Node node, long address, byte value) { try { ByteArraySupport.littleEndian().putByte(buffer(), address, value); @@ -296,7 +304,7 @@ public void store_i32_8(Node node, long address, byte value) { } } - @Override + @ExportMessage public void store_i32_16(Node node, long address, short value) { try { ByteArraySupport.littleEndian().putShort(buffer(), address, value); @@ -305,7 +313,7 @@ public void store_i32_16(Node node, long address, short value) { } } - @Override + @ExportMessage public void store_i64_8(Node node, long address, byte value) { try { ByteArraySupport.littleEndian().putByte(buffer(), address, value); @@ -314,7 +322,7 @@ public void store_i64_8(Node node, long address, byte value) { } } - @Override + @ExportMessage public void store_i64_16(Node node, long address, short value) { try { ByteArraySupport.littleEndian().putShort(buffer(), address, value); @@ -323,7 +331,7 @@ public void store_i64_16(Node node, long address, short value) { } } - @Override + @ExportMessage public void store_i64_32(Node node, long address, int value) { try { ByteArraySupport.littleEndian().putInt(buffer(), address, value); @@ -332,7 +340,7 @@ public void store_i64_32(Node node, long address, int value) { } } - @Override + @ExportMessage public void store_i128(Node node, long address, Vector128 value) { if (ByteArraySupport.littleEndian().inBounds(buffer(), address, 16)) { System.arraycopy(value.getBytes(), 0, buffer(), (int) address, 16); @@ -348,7 +356,7 @@ private static void validateAtomicAddress(Node node, long address, int length) { } } - @Override + @ExportMessage public int atomic_load_i32(Node node, long address) { validateAtomicAddress(node, address, 4); try { @@ -358,7 +366,7 @@ public int atomic_load_i32(Node node, long address) { } } - @Override + @ExportMessage public long atomic_load_i64(Node node, long address) { validateAtomicAddress(node, address, 8); try { @@ -368,7 +376,7 @@ public long atomic_load_i64(Node node, long address) { } } - @Override + @ExportMessage public int atomic_load_i32_8u(Node node, long address) { validateAtomicAddress(node, address, 1); try { @@ -378,7 +386,7 @@ public int atomic_load_i32_8u(Node node, long address) { } } - @Override + @ExportMessage public int atomic_load_i32_16u(Node node, long address) { validateAtomicAddress(node, address, 2); try { @@ -388,7 +396,7 @@ public int atomic_load_i32_16u(Node node, long address) { } } - @Override + @ExportMessage public long atomic_load_i64_8u(Node node, long address) { validateAtomicAddress(node, address, 1); try { @@ -398,7 +406,7 @@ public long atomic_load_i64_8u(Node node, long address) { } } - @Override + @ExportMessage public long atomic_load_i64_16u(Node node, long address) { validateAtomicAddress(node, address, 2); try { @@ -408,7 +416,7 @@ public long atomic_load_i64_16u(Node node, long address) { } } - @Override + @ExportMessage public long atomic_load_i64_32u(Node node, long address) { validateAtomicAddress(node, address, 4); try { @@ -418,7 +426,7 @@ public long atomic_load_i64_32u(Node node, long address) { } } - @Override + @ExportMessage public void atomic_store_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -428,7 +436,7 @@ public void atomic_store_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public void atomic_store_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -438,7 +446,7 @@ public void atomic_store_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public void atomic_store_i32_8(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -448,7 +456,7 @@ public void atomic_store_i32_8(Node node, long address, byte value) { } } - @Override + @ExportMessage public void atomic_store_i32_16(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -458,7 +466,7 @@ public void atomic_store_i32_16(Node node, long address, short value) { } } - @Override + @ExportMessage public void atomic_store_i64_8(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -468,7 +476,7 @@ public void atomic_store_i64_8(Node node, long address, byte value) { } } - @Override + @ExportMessage public void atomic_store_i64_16(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -478,7 +486,7 @@ public void atomic_store_i64_16(Node node, long address, short value) { } } - @Override + @ExportMessage public void atomic_store_i64_32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -488,7 +496,7 @@ public void atomic_store_i64_32(Node node, long address, int value) { } } - @Override + @ExportMessage public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -498,7 +506,7 @@ public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_add_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -508,7 +516,7 @@ public int atomic_rmw_add_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_add_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -518,7 +526,7 @@ public int atomic_rmw_add_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -528,7 +536,7 @@ public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_add_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -538,7 +546,7 @@ public long atomic_rmw_add_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_add_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -548,7 +556,7 @@ public long atomic_rmw_add_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_add_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -558,7 +566,7 @@ public long atomic_rmw_add_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -568,7 +576,7 @@ public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -578,7 +586,7 @@ public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_sub_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -588,7 +596,7 @@ public int atomic_rmw_sub_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -598,7 +606,7 @@ public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -608,7 +616,7 @@ public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -618,7 +626,7 @@ public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_sub_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -628,7 +636,7 @@ public long atomic_rmw_sub_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -638,7 +646,7 @@ public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_and_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -648,7 +656,7 @@ public int atomic_rmw_and_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_and_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -658,7 +666,7 @@ public int atomic_rmw_and_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -668,7 +676,7 @@ public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_and_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -678,7 +686,7 @@ public long atomic_rmw_and_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_and_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -688,7 +696,7 @@ public long atomic_rmw_and_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_and_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -698,7 +706,7 @@ public long atomic_rmw_and_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -708,7 +716,7 @@ public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_or_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -718,7 +726,7 @@ public int atomic_rmw_or_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_or_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -728,7 +736,7 @@ public int atomic_rmw_or_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -738,7 +746,7 @@ public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_or_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -748,7 +756,7 @@ public long atomic_rmw_or_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_or_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -758,7 +766,7 @@ public long atomic_rmw_or_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_or_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -768,7 +776,7 @@ public long atomic_rmw_or_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -778,7 +786,7 @@ public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -788,7 +796,7 @@ public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_xor_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -798,7 +806,7 @@ public int atomic_rmw_xor_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -808,7 +816,7 @@ public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -818,7 +826,7 @@ public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -828,7 +836,7 @@ public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_xor_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -838,7 +846,7 @@ public long atomic_rmw_xor_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -848,7 +856,7 @@ public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -858,7 +866,7 @@ public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public int atomic_rmw_xchg_i32(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -868,7 +876,7 @@ public int atomic_rmw_xchg_i32(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { validateAtomicAddress(node, address, 1); try { @@ -878,7 +886,7 @@ public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { } } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { validateAtomicAddress(node, address, 2); try { @@ -888,7 +896,7 @@ public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { } } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { validateAtomicAddress(node, address, 4); try { @@ -898,7 +906,7 @@ public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { } } - @Override + @ExportMessage public long atomic_rmw_xchg_i64(Node node, long address, long value) { validateAtomicAddress(node, address, 8); try { @@ -908,7 +916,7 @@ public long atomic_rmw_xchg_i64(Node node, long address, long value) { } } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byte replacement) { validateAtomicAddress(node, address, 1); try { @@ -918,7 +926,7 @@ public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byt } } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, short replacement) { validateAtomicAddress(node, address, 2); try { @@ -928,7 +936,7 @@ public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, s } } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int replacement) { validateAtomicAddress(node, address, 4); try { @@ -938,7 +946,7 @@ public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int rep } } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, byte replacement) { validateAtomicAddress(node, address, 1); try { @@ -948,7 +956,7 @@ public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, by } } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, short replacement) { validateAtomicAddress(node, address, 2); try { @@ -958,7 +966,7 @@ public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, } } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, int replacement) { validateAtomicAddress(node, address, 4); try { @@ -968,7 +976,7 @@ public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, in } } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long replacement) { validateAtomicAddress(node, address, 8); try { @@ -978,7 +986,7 @@ public long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long } } - @Override + @ExportMessage @TruffleBoundary public int atomic_notify(Node node, long address, int count) { validateAtomicAddress(node, address, 4); @@ -991,7 +999,7 @@ public int atomic_notify(Node node, long address, int count) { return invokeNotifyCallback(node, address, count); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait32(Node node, long address, int expected, long timeout) { validateAtomicAddress(node, address, 4); @@ -1004,7 +1012,7 @@ public int atomic_wait32(Node node, long address, int expected, long timeout) { return invokeWaitCallback(node, address, expected, timeout, false); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait64(Node node, long address, long expected, long timeout) { validateAtomicAddress(node, address, 8); @@ -1016,21 +1024,22 @@ public int atomic_wait64(Node node, long address, long expected, long timeout) { } return invokeWaitCallback(node, address, expected, timeout, true); } + // Checkstyle: resume - @Override + @ExportMessage public void initialize(byte[] source, int sourceOffset, long destinationOffset, int length) { assert destinationOffset + length <= byteSize(); System.arraycopy(source, sourceOffset, buffer(), (int) destinationOffset, length); } - @Override + @ExportMessage @TruffleBoundary public void fill(long offset, long length, byte value) { assert offset + length <= byteSize(); Arrays.fill(buffer(), (int) offset, (int) (offset + length), value); } - @Override + @ExportMessage public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffset, long length) { assert source instanceof ByteArrayWasmMemory; assert destinationOffset < byteSize(); @@ -1038,24 +1047,27 @@ public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffse System.arraycopy(s.buffer(), (int) sourceOffset, buffer(), (int) destinationOffset, (int) length); } - @Override + @ExportMessage public WasmMemory duplicate() { final ByteArrayWasmMemory other = new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, size(), maxAllowedSize, indexType64, shared); System.arraycopy(buffer(), 0, other.buffer(), 0, (int) byteSize()); return other; } - @Override + @ExportMessage public void close() { dynamicBuffer = null; } - @Override - public ByteBuffer asByteBuffer() { - return null; + private boolean outOfBounds(int offset, int length) { + return length < 0 || offset < 0 || offset > byteSize() - length; + } + + private boolean outOfBounds(long offset, long length) { + return length < 0 || offset < 0 || offset > byteSize() - length; } - @Override + @ExportMessage @TruffleBoundary public int copyFromStream(Node node, InputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -1064,7 +1076,7 @@ public int copyFromStream(Node node, InputStream stream, int offset, int length) return stream.read(buffer(), offset, length); } - @Override + @ExportMessage @TruffleBoundary public void copyToStream(Node node, OutputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -1073,7 +1085,7 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) stream.write(buffer(), offset, length); } - @Override + @ExportMessage public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java index ee8f51e96299..5f16f7255c3e 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/NativeWasmMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -48,9 +48,12 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.lang.reflect.Field; -import java.nio.ByteBuffer; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import org.graalvm.wasm.WasmMath; import org.graalvm.wasm.api.Vector128; +import org.graalvm.wasm.constants.Sizes; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; @@ -60,14 +63,18 @@ import sun.misc.Unsafe; +@ExportLibrary(WasmMemoryLibrary.class) final class NativeWasmMemory extends WasmMemory { private long startAddress; private long size; + public static final long MAX_ALLOWED_SIZE = Sizes.MAX_MEMORY_64_INSTANCE_SIZE; + private static final Unsafe unsafe; private static final VarHandle SIZE_FIELD; + @TruffleBoundary private NativeWasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64, boolean shared) { super(declaredMinSize, declaredMaxSize, initialSize, maxAllowedSize, indexType64, shared); this.size = declaredMinSize; @@ -75,8 +82,9 @@ private NativeWasmMemory(long declaredMinSize, long declaredMaxSize, long initia this.startAddress = allocate(byteSize); } - NativeWasmMemory(long declaredMinSize, long declaredMaxSize, long maxAllowedSize, boolean indexType64, boolean shared) { - this(declaredMinSize, declaredMaxSize, declaredMinSize, maxAllowedSize, indexType64, shared); + @TruffleBoundary + NativeWasmMemory(long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared) { + this(declaredMinSize, declaredMaxSize, declaredMinSize, WasmMath.minUnsigned(declaredMaxSize, MAX_ALLOWED_SIZE), indexType64, shared); } private static long allocate(long byteSize) { @@ -89,26 +97,26 @@ private static long allocate(long byteSize) { } } - @Override + @ExportMessage public long size() { return (long) SIZE_FIELD.getVolatile(this); } - @Override + @ExportMessage public long byteSize() { return size * MEMORY_PAGE_SIZE; } @TruffleBoundary - @Override + @ExportMessage public synchronized long grow(long extraPageSize) { final long previousSize = size(); if (extraPageSize == 0) { invokeGrowCallback(); return previousSize; - } else if (Long.compareUnsigned(extraPageSize, maxAllowedSize) <= 0 && Long.compareUnsigned(previousSize + extraPageSize, maxAllowedSize) <= 0) { - // Condition above and limit on maxPageSize (see ModuleLimits#MAX_MEMORY_SIZE) ensure - // computation of targetByteSize does not overflow. + } else if (Long.compareUnsigned(extraPageSize, maxAllowedSize()) <= 0 && Long.compareUnsigned(previousSize + extraPageSize, maxAllowedSize()) <= 0) { + // Condition above and limit on maxAllowedSize (see NativeWasmMemory#MAX_ALLOWED_SIZE) + // ensure computation of targetByteSize does not overflow. final long targetByteSize = Math.multiplyExact(Math.addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE); final long updatedSize = previousSize + extraPageSize; try { @@ -126,7 +134,7 @@ public synchronized long grow(long extraPageSize) { } } - @Override + @ExportMessage @TruffleBoundary public void reset() { free(); @@ -152,91 +160,92 @@ private static void validateAtomicAddress(Node node, long address, int length) { } } - @Override + // Checkstyle: stop + @ExportMessage public int load_i32(Node node, long address) { validateAddress(node, address, 4); return unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public long load_i64(Node node, long address) { validateAddress(node, address, 8); return unsafe.getLong(startAddress + address); } - @Override + @ExportMessage public float load_f32(Node node, long address) { validateAddress(node, address, 4); return unsafe.getFloat(startAddress + address); } - @Override + @ExportMessage public double load_f64(Node node, long address) { validateAddress(node, address, 8); return unsafe.getDouble(startAddress + address); } - @Override + @ExportMessage public int load_i32_8s(Node node, long address) { validateAddress(node, address, 1); return unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public int load_i32_8u(Node node, long address) { validateAddress(node, address, 1); return 0x0000_00ff & unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public int load_i32_16s(Node node, long address) { validateAddress(node, address, 2); return unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public int load_i32_16u(Node node, long address) { validateAddress(node, address, 2); return 0x0000_ffff & unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_8s(Node node, long address) { validateAddress(node, address, 1); return unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public long load_i64_8u(Node node, long address) { validateAddress(node, address, 1); return 0x0000_0000_0000_00ffL & unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public long load_i64_16s(Node node, long address) { validateAddress(node, address, 2); return unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_16u(Node node, long address) { validateAddress(node, address, 2); return 0x0000_0000_0000_ffffL & unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_32s(Node node, long address) { validateAddress(node, address, 4); return unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public long load_i64_32u(Node node, long address) { validateAddress(node, address, 4); return 0x0000_0000_ffff_ffffL & unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public Vector128 load_i128(Node node, long address) { validateAddress(node, address, Vector128.BYTES); byte[] bytes = new byte[Vector128.BYTES]; @@ -244,165 +253,165 @@ public Vector128 load_i128(Node node, long address) { return new Vector128(bytes); } - @Override + @ExportMessage public void store_i32(Node node, long address, int value) { validateAddress(node, address, 4); unsafe.putInt(startAddress + address, value); } - @Override + @ExportMessage public void store_i64(Node node, long address, long value) { validateAddress(node, address, 8); unsafe.putLong(startAddress + address, value); } - @Override + @ExportMessage public void store_f32(Node node, long address, float value) { validateAddress(node, address, 4); unsafe.putFloat(startAddress + address, value); } - @Override + @ExportMessage public void store_f64(Node node, long address, double value) { validateAddress(node, address, 8); unsafe.putDouble(startAddress + address, value); } - @Override + @ExportMessage public void store_i32_8(Node node, long address, byte value) { validateAddress(node, address, 1); unsafe.putByte(startAddress + address, value); } - @Override + @ExportMessage public void store_i32_16(Node node, long address, short value) { validateAddress(node, address, 2); unsafe.putShort(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_8(Node node, long address, byte value) { validateAddress(node, address, 1); unsafe.putByte(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_16(Node node, long address, short value) { validateAddress(node, address, 2); unsafe.putShort(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_32(Node node, long address, int value) { validateAddress(node, address, 4); unsafe.putInt(startAddress + address, value); } - @Override + @ExportMessage public void store_i128(Node node, long address, Vector128 value) { validateAddress(node, address, 16); unsafe.copyMemory(value.getBytes(), Unsafe.ARRAY_BYTE_BASE_OFFSET, null, startAddress + address, 16); } - @Override + @ExportMessage public int atomic_load_i32(Node node, long address) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getIntVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64(Node node, long address) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getLongVolatile(null, startAddress + address); } - @Override + @ExportMessage public int atomic_load_i32_8u(Node node, long address) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); return 0x0000_00ff & unsafe.getByteVolatile(null, startAddress + address); } - @Override + @ExportMessage public int atomic_load_i32_16u(Node node, long address) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); return 0x0000_ffff & unsafe.getShortVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_8u(Node node, long address) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); return 0x0000_0000_0000_00ffL & unsafe.getByteVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_16u(Node node, long address) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); return 0x0000_0000_0000_ffffL & unsafe.getShortVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_32u(Node node, long address) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return 0x0000_0000_ffff_ffffL & unsafe.getIntVolatile(null, startAddress + address); } - @Override + @ExportMessage public void atomic_store_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); unsafe.putIntVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); unsafe.putLongVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i32_8(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); unsafe.putByteVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i32_16(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); unsafe.putShortVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_8(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); unsafe.putByteVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_16(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); unsafe.putShortVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); unsafe.putIntVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -413,7 +422,7 @@ public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_add_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -424,14 +433,14 @@ public int atomic_rmw_add_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_add_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndAddInt(null, startAddress + address, value); } - @Override + @ExportMessage public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -442,7 +451,7 @@ public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -453,7 +462,7 @@ public long atomic_rmw_add_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -461,14 +470,14 @@ public long atomic_rmw_add_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndAddLong(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -479,7 +488,7 @@ public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -490,14 +499,14 @@ public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_sub_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndAddInt(null, startAddress + address, -value); } - @Override + @ExportMessage public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -508,7 +517,7 @@ public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -519,7 +528,7 @@ public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -527,14 +536,14 @@ public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndAddLong(null, startAddress + address, -value); } - @Override + @ExportMessage public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -545,7 +554,7 @@ public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_and_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -556,7 +565,7 @@ public int atomic_rmw_and_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_and_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -567,7 +576,7 @@ public int atomic_rmw_and_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -578,7 +587,7 @@ public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -589,7 +598,7 @@ public long atomic_rmw_and_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -600,7 +609,7 @@ public long atomic_rmw_and_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -611,7 +620,7 @@ public long atomic_rmw_and_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -622,7 +631,7 @@ public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_or_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -633,7 +642,7 @@ public int atomic_rmw_or_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_or_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -644,7 +653,7 @@ public int atomic_rmw_or_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -655,7 +664,7 @@ public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -666,7 +675,7 @@ public long atomic_rmw_or_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -677,7 +686,7 @@ public long atomic_rmw_or_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -688,7 +697,7 @@ public long atomic_rmw_or_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -699,7 +708,7 @@ public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -710,7 +719,7 @@ public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -721,7 +730,7 @@ public int atomic_rmw_xor_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -732,7 +741,7 @@ public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -743,7 +752,7 @@ public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -754,7 +763,7 @@ public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -765,7 +774,7 @@ public long atomic_rmw_xor_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -776,7 +785,7 @@ public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -787,14 +796,14 @@ public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndSetInt(null, startAddress + address, value); } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -805,7 +814,7 @@ public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -816,7 +825,7 @@ public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -824,14 +833,14 @@ public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndSetLong(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byte replacement) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -839,7 +848,7 @@ public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byt return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, short replacement) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -847,14 +856,14 @@ public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, s return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int replacement) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return UnsafeUtilities.compareAndExchangeInt(startAddress, address, expected, replacement); } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, byte replacement) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -862,7 +871,7 @@ public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, by return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, short replacement) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -870,7 +879,7 @@ public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, int replacement) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -878,14 +887,14 @@ public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, in return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long replacement) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return UnsafeUtilities.compareAndExchangeLong(startAddress, address, expected, replacement); } - @Override + @ExportMessage @TruffleBoundary public int atomic_notify(Node node, long address, int count) { validateAddress(node, address, 4); @@ -896,7 +905,7 @@ public int atomic_notify(Node node, long address, int count) { return invokeNotifyCallback(node, address, count); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait32(Node node, long address, int expected, long timeout) { validateAddress(node, address, 4); @@ -907,7 +916,7 @@ public int atomic_wait32(Node node, long address, int expected, long timeout) { return invokeWaitCallback(node, address, expected, timeout, false); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait64(Node node, long address, long expected, long timeout) { validateAddress(node, address, 8); @@ -917,32 +926,33 @@ public int atomic_wait64(Node node, long address, long expected, long timeout) { } return invokeWaitCallback(node, address, expected, timeout, true); } + // Checkstyle: resume - @Override + @ExportMessage public WasmMemory duplicate() { final NativeWasmMemory other = new NativeWasmMemory(declaredMinSize, declaredMaxSize, size, maxAllowedSize, indexType64, shared); unsafe.copyMemory(this.startAddress, other.startAddress, this.byteSize()); return other; } - @Override + @ExportMessage public void initialize(byte[] source, int sourceOffset, long destinationOffset, int length) { for (int i = 0; i < length; i++) { unsafe.putByte(startAddress + destinationOffset + i, source[sourceOffset + i]); } } - @Override + @ExportMessage public void initializeUnsafe(long sourceAddress, int sourceOffset, long destinationOffset, int length) { unsafe.copyMemory(sourceAddress + sourceOffset, startAddress + destinationOffset, length); } - @Override + @ExportMessage public void fill(long offset, long length, byte value) { unsafe.setMemory(startAddress + offset, length, value); } - @Override + @ExportMessage public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffset, long length) { assert source instanceof NativeWasmMemory; final NativeWasmMemory s = (NativeWasmMemory) source; @@ -961,19 +971,22 @@ private void free() { size = 0; } - @Override + @ExportMessage public void close() { if (!freed()) { free(); } } - @Override - public ByteBuffer asByteBuffer() { - return null; + private boolean outOfBounds(int offset, int length) { + return length < 0 || offset < 0 || offset > byteSize() - length; } - @Override + private boolean outOfBounds(long offset, long length) { + return length < 0 || offset < 0 || offset > byteSize() - length; + } + + @ExportMessage @TruffleBoundary public int copyFromStream(Node node, InputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -994,7 +1007,7 @@ public int copyFromStream(Node node, InputStream stream, int offset, int length) return totalBytesRead; } - @Override + @ExportMessage @TruffleBoundary public void copyToStream(Node node, OutputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -1006,7 +1019,7 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) } } - @Override + @ExportMessage public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java index c820938fb807..e1d49019a9b3 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/UnsafeWasmMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,8 @@ package org.graalvm.wasm.memory; import static java.lang.Long.compareUnsigned; -import static java.lang.StrictMath.addExact; -import static java.lang.StrictMath.multiplyExact; +import static java.lang.Math.addExact; +import static java.lang.Math.multiplyExact; import static org.graalvm.wasm.constants.Sizes.MEMORY_PAGE_SIZE; import java.io.IOException; @@ -54,6 +54,8 @@ import java.nio.Buffer; import java.nio.ByteBuffer; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; import org.graalvm.wasm.api.Vector128; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; @@ -64,6 +66,7 @@ import sun.misc.Unsafe; +@ExportLibrary(WasmMemoryLibrary.class) public final class UnsafeWasmMemory extends WasmMemory { private long startAddress; @@ -71,10 +74,13 @@ public final class UnsafeWasmMemory extends WasmMemory { private ByteBuffer buffer; + public static final long MAX_ALLOWED_SIZE = Integer.MAX_VALUE / MEMORY_PAGE_SIZE; + private static final Unsafe unsafe; private static final long addressOffset; private static final VarHandle SIZE_FIELD; + @TruffleBoundary private UnsafeWasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64, boolean shared) { super(declaredMinSize, declaredMaxSize, initialSize, maxAllowedSize, indexType64, shared); this.size = declaredMinSize; @@ -83,8 +89,9 @@ private UnsafeWasmMemory(long declaredMinSize, long declaredMaxSize, long initia this.startAddress = getBufferAddress(buffer); } - UnsafeWasmMemory(long declaredMinSize, long declaredMaxSize, long maxAllowedSize, boolean indexType64, boolean shared) { - this(declaredMinSize, declaredMaxSize, declaredMinSize, maxAllowedSize, indexType64, shared); + @TruffleBoundary + UnsafeWasmMemory(long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared) { + this(declaredMinSize, declaredMaxSize, declaredMinSize, Math.min(declaredMaxSize, MAX_ALLOWED_SIZE), indexType64, shared); } @TruffleBoundary @@ -118,7 +125,7 @@ private static void validateAtomicAddress(Node node, long address, int length) { } } - @Override + @ExportMessage @TruffleBoundary public void reset() { size = declaredMinSize; @@ -127,26 +134,26 @@ public void reset() { currentMinSize = declaredMinSize; } - @Override + @ExportMessage public long size() { return (long) SIZE_FIELD.getVolatile(this); } - @Override + @ExportMessage public long byteSize() { return size * MEMORY_PAGE_SIZE; } - @Override + @ExportMessage @TruffleBoundary public synchronized long grow(long extraPageSize) { final long previousSize = size(); if (extraPageSize == 0) { invokeGrowCallback(); return previousSize; - } else if (compareUnsigned(extraPageSize, maxAllowedSize) <= 0 && compareUnsigned(previousSize + extraPageSize, maxAllowedSize) <= 0) { - // Condition above and limit on maxPageSize (see ModuleLimits#MAX_MEMORY_SIZE) ensure - // computation of targetByteSize does not overflow. + } else if (compareUnsigned(extraPageSize, maxAllowedSize()) <= 0 && compareUnsigned(previousSize + extraPageSize, maxAllowedSize()) <= 0) { + // Condition above and limit on maxAllowedSize (see UnsafeWasmMemory#MAX_ALLOWED_SIZE) + // ensure computation of targetByteSize does not overflow. final long targetByteSize = multiplyExact(addExact(previousSize, extraPageSize), MEMORY_PAGE_SIZE); final long sourceByteSize = byteSize(); ByteBuffer updatedBuffer = allocateBuffer(targetByteSize); @@ -164,91 +171,92 @@ public synchronized long grow(long extraPageSize) { } } - @Override + // Checkstyle: stop + @ExportMessage public int load_i32(Node node, long address) { validateAddress(node, address, 4); return unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public long load_i64(Node node, long address) { validateAddress(node, address, 8); return unsafe.getLong(startAddress + address); } - @Override + @ExportMessage public float load_f32(Node node, long address) { validateAddress(node, address, 4); return unsafe.getFloat(startAddress + address); } - @Override + @ExportMessage public double load_f64(Node node, long address) { validateAddress(node, address, 8); return unsafe.getDouble(startAddress + address); } - @Override + @ExportMessage public int load_i32_8s(Node node, long address) { validateAddress(node, address, 1); return unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public int load_i32_8u(Node node, long address) { validateAddress(node, address, 1); return 0x0000_00ff & unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public int load_i32_16s(Node node, long address) { validateAddress(node, address, 2); return unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public int load_i32_16u(Node node, long address) { validateAddress(node, address, 2); return 0x0000_ffff & unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_8s(Node node, long address) { validateAddress(node, address, 1); return unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public long load_i64_8u(Node node, long address) { validateAddress(node, address, 1); return 0x0000_0000_0000_00ffL & unsafe.getByte(startAddress + address); } - @Override + @ExportMessage public long load_i64_16s(Node node, long address) { validateAddress(node, address, 2); return unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_16u(Node node, long address) { validateAddress(node, address, 2); return 0x0000_0000_0000_ffffL & unsafe.getShort(startAddress + address); } - @Override + @ExportMessage public long load_i64_32s(Node node, long address) { validateAddress(node, address, 4); return unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public long load_i64_32u(Node node, long address) { validateAddress(node, address, 4); return 0x0000_0000_ffff_ffffL & unsafe.getInt(startAddress + address); } - @Override + @ExportMessage public Vector128 load_i128(Node node, long address) { validateAddress(node, address, Vector128.BYTES); byte[] bytes = new byte[Vector128.BYTES]; @@ -256,167 +264,167 @@ public Vector128 load_i128(Node node, long address) { return new Vector128(bytes); } - @Override + @ExportMessage public void store_i32(Node node, long address, int value) { validateAddress(node, address, 4); unsafe.putInt(startAddress + address, value); } - @Override + @ExportMessage public void store_i64(Node node, long address, long value) { validateAddress(node, address, 8); unsafe.putLong(startAddress + address, value); } - @Override + @ExportMessage public void store_f32(Node node, long address, float value) { validateAddress(node, address, 4); unsafe.putFloat(startAddress + address, value); } - @Override + @ExportMessage public void store_f64(Node node, long address, double value) { validateAddress(node, address, 8); unsafe.putDouble(startAddress + address, value); } - @Override + @ExportMessage public void store_i32_8(Node node, long address, byte value) { validateAddress(node, address, 1); unsafe.putByte(startAddress + address, value); } - @Override + @ExportMessage public void store_i32_16(Node node, long address, short value) { validateAddress(node, address, 2); unsafe.putShort(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_8(Node node, long address, byte value) { validateAddress(node, address, 1); unsafe.putByte(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_16(Node node, long address, short value) { validateAddress(node, address, 2); unsafe.putShort(startAddress + address, value); } - @Override + @ExportMessage public void store_i64_32(Node node, long address, int value) { validateAddress(node, address, 4); unsafe.putInt(startAddress + address, value); } - @Override + @ExportMessage public void store_i128(Node node, long address, Vector128 value) { validateAddress(node, address, 16); unsafe.copyMemory(value.getBytes(), Unsafe.ARRAY_BYTE_BASE_OFFSET, null, startAddress + address, 16); } - @Override + @ExportMessage public int atomic_load_i32(Node node, long address) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getIntVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64(Node node, long address) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getLongVolatile(null, startAddress + address); } - @Override + @ExportMessage public int atomic_load_i32_8u(Node node, long address) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); return 0x0000_00ff & unsafe.getByteVolatile(null, startAddress + address); } - @Override + @ExportMessage public int atomic_load_i32_16u(Node node, long address) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); return 0x0000_ffff & unsafe.getShortVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_8u(Node node, long address) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); return 0x0000_0000_0000_00ffL & unsafe.getByteVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_16u(Node node, long address) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); return 0x0000_0000_0000_ffffL & unsafe.getShortVolatile(null, startAddress + address); } - @Override + @ExportMessage public long atomic_load_i64_32u(Node node, long address) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return 0x0000_0000_ffff_ffffL & unsafe.getIntVolatile(null, startAddress + address); } - @Override + @ExportMessage public void atomic_store_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); unsafe.putIntVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); unsafe.putLongVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i32_8(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); unsafe.putByteVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i32_16(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); unsafe.putShortVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_8(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); unsafe.putByteVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_16(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); unsafe.putShortVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public void atomic_store_i64_32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); unsafe.putIntVolatile(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -427,7 +435,7 @@ public int atomic_rmw_add_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_add_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -438,14 +446,14 @@ public int atomic_rmw_add_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_add_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndAddInt(null, startAddress + address, value); } - @Override + @ExportMessage public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -456,7 +464,7 @@ public long atomic_rmw_add_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -467,7 +475,7 @@ public long atomic_rmw_add_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -475,14 +483,14 @@ public long atomic_rmw_add_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_add_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndAddLong(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -493,7 +501,7 @@ public int atomic_rmw_sub_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -504,14 +512,14 @@ public int atomic_rmw_sub_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_sub_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndAddInt(null, startAddress + address, -value); } - @Override + @ExportMessage public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -522,7 +530,7 @@ public long atomic_rmw_sub_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -533,7 +541,7 @@ public long atomic_rmw_sub_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -541,14 +549,14 @@ public long atomic_rmw_sub_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_sub_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndAddLong(null, startAddress + address, -value); } - @Override + @ExportMessage public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -559,7 +567,7 @@ public int atomic_rmw_and_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_and_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -570,7 +578,7 @@ public int atomic_rmw_and_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_and_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -581,7 +589,7 @@ public int atomic_rmw_and_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -592,7 +600,7 @@ public long atomic_rmw_and_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -603,7 +611,7 @@ public long atomic_rmw_and_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -614,7 +622,7 @@ public long atomic_rmw_and_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_and_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -625,7 +633,7 @@ public long atomic_rmw_and_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -636,7 +644,7 @@ public int atomic_rmw_or_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_or_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -647,7 +655,7 @@ public int atomic_rmw_or_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_or_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -658,7 +666,7 @@ public int atomic_rmw_or_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -669,7 +677,7 @@ public long atomic_rmw_or_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -680,7 +688,7 @@ public long atomic_rmw_or_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -691,7 +699,7 @@ public long atomic_rmw_or_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_or_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -702,7 +710,7 @@ public long atomic_rmw_or_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -713,7 +721,7 @@ public int atomic_rmw_xor_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -724,7 +732,7 @@ public int atomic_rmw_xor_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_xor_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -735,7 +743,7 @@ public int atomic_rmw_xor_i32(Node node, long address, int value) { return v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -746,7 +754,7 @@ public long atomic_rmw_xor_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -757,7 +765,7 @@ public long atomic_rmw_xor_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -768,7 +776,7 @@ public long atomic_rmw_xor_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xor_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); @@ -779,7 +787,7 @@ public long atomic_rmw_xor_i64(Node node, long address, long value) { return v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -790,7 +798,7 @@ public int atomic_rmw_xchg_i32_8u(Node node, long address, byte value) { return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -801,14 +809,14 @@ public int atomic_rmw_xchg_i32_16u(Node node, long address, short value) { return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_xchg_i32(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return unsafe.getAndSetInt(null, startAddress + address, value); } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -819,7 +827,7 @@ public long atomic_rmw_xchg_i64_8u(Node node, long address, byte value) { return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -830,7 +838,7 @@ public long atomic_rmw_xchg_i64_16u(Node node, long address, short value) { return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -838,14 +846,14 @@ public long atomic_rmw_xchg_i64_32u(Node node, long address, int value) { return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_xchg_i64(Node node, long address, long value) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return unsafe.getAndSetLong(null, startAddress + address, value); } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byte replacement) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -853,7 +861,7 @@ public int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byt return 0x0000_00ff & v; } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, short replacement) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -861,14 +869,14 @@ public int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, s return 0x0000_ffff & v; } - @Override + @ExportMessage public int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int replacement) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); return UnsafeUtilities.compareAndExchangeInt(startAddress, address, expected, replacement); } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, byte replacement) { validateAddress(node, address, 1); validateAtomicAddress(node, address, 1); @@ -876,7 +884,7 @@ public long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, by return 0x0000_0000_0000_00ffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, short replacement) { validateAddress(node, address, 2); validateAtomicAddress(node, address, 2); @@ -884,7 +892,7 @@ public long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, return 0x0000_0000_0000_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, int replacement) { validateAddress(node, address, 4); validateAtomicAddress(node, address, 4); @@ -892,14 +900,14 @@ public long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, in return 0x0000_0000_ffff_ffffL & v; } - @Override + @ExportMessage public long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long replacement) { validateAddress(node, address, 8); validateAtomicAddress(node, address, 8); return UnsafeUtilities.compareAndExchangeLong(startAddress, address, expected, replacement); } - @Override + @ExportMessage @TruffleBoundary public int atomic_notify(Node node, long address, int count) { validateAddress(node, address, 4); @@ -910,7 +918,7 @@ public int atomic_notify(Node node, long address, int count) { return invokeNotifyCallback(node, address, count); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait32(Node node, long address, int expected, long timeout) { validateAddress(node, address, 4); @@ -921,7 +929,7 @@ public int atomic_wait32(Node node, long address, int expected, long timeout) { return invokeWaitCallback(node, address, expected, timeout, false); } - @Override + @ExportMessage @TruffleBoundary public int atomic_wait64(Node node, long address, long expected, long timeout) { validateAddress(node, address, 8); @@ -931,27 +939,28 @@ public int atomic_wait64(Node node, long address, long expected, long timeout) { } return invokeWaitCallback(node, address, expected, timeout, true); } + // Checkstyle: resume - @Override + @ExportMessage public void initialize(byte[] source, int sourceOffset, long destinationOffset, int length) { for (int i = 0; i < length; i++) { unsafe.putByte(startAddress + destinationOffset + i, source[sourceOffset + i]); } } - @Override + @ExportMessage public void initializeUnsafe(long sourceAddress, int sourceOffset, long destinationOffset, int length) { assert destinationOffset + length <= byteSize(); unsafe.copyMemory(sourceAddress + sourceOffset, startAddress + destinationOffset, length); } - @Override + @ExportMessage public void fill(long offset, long length, byte value) { assert offset + length <= byteSize(); unsafe.setMemory(startAddress + offset, length, value); } - @Override + @ExportMessage public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffset, long length) { assert source instanceof UnsafeWasmMemory; assert destinationOffset + length < byteSize(); @@ -959,7 +968,7 @@ public void copyFrom(WasmMemory source, long sourceOffset, long destinationOffse unsafe.copyMemory(s.startAddress + sourceOffset, this.startAddress + destinationOffset, length); } - @Override + @ExportMessage public WasmMemory duplicate() { final UnsafeWasmMemory other = new UnsafeWasmMemory(declaredMinSize, declaredMaxSize, size, maxAllowedSize, indexType64, shared); unsafe.copyMemory(this.startAddress, other.startAddress, this.byteSize()); @@ -977,19 +986,28 @@ public boolean freed() { return startAddress == 0; } - @Override + @ExportMessage public void close() { if (!freed()) { free(); } } - @Override + @ExportMessage + @TruffleBoundary public ByteBuffer asByteBuffer() { return buffer.duplicate(); } - @Override + private boolean outOfBounds(int offset, int length) { + return length < 0 || offset < 0 || offset > byteSize() - length; + } + + private boolean outOfBounds(long offset, long length) { + return length < 0 || offset < 0 || offset > byteSize() - length; + } + + @ExportMessage @TruffleBoundary public int copyFromStream(Node node, InputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -1010,7 +1028,7 @@ public int copyFromStream(Node node, InputStream stream, int offset, int length) return totalBytesRead; } - @Override + @ExportMessage @TruffleBoundary public void copyToStream(Node node, OutputStream stream, int offset, int length) throws IOException { if (outOfBounds(offset, length)) { @@ -1022,7 +1040,7 @@ public void copyToStream(Node node, OutputStream stream, int offset, int length) } } - @Override + @ExportMessage public void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length) { if (outOfBounds(srcOffset, length)) { throw trapOutOfBounds(node, srcOffset, length); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java index 57b92445243a..2809719193c2 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,20 +41,16 @@ package org.graalvm.wasm.memory; import static java.lang.Long.compareUnsigned; +import static org.graalvm.wasm.Assert.assertUnsignedLongLessOrEqual; import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_64_DECLARATION_SIZE; import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_64_INSTANCE_SIZE; import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_DECLARATION_SIZE; import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_INSTANCE_SIZE; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import org.graalvm.wasm.EmbedderDataHolder; -import org.graalvm.wasm.api.Vector128; import org.graalvm.wasm.api.WebAssembly; import org.graalvm.wasm.collection.ByteArrayList; import org.graalvm.wasm.constants.Sizes; @@ -101,9 +97,8 @@ public abstract class WasmMemory extends EmbedderDataHolder implements TruffleOb * The maximum practical size of this memory instance (measured in number of * {@link Sizes#MEMORY_PAGE_SIZE pages}). *

- * It is the minimum between {@link #declaredMaxSize the limit defined in the module binary}, - * {@link Sizes#MAX_MEMORY_INSTANCE_SIZE the GraalWasm limit} and any additional limit (the JS - * API for example has lower limits). + * It is the minimum between {@link #declaredMaxSize the limit defined in the module binary} and + * the limit imposed by the implementation. *

* This is different from {@link #declaredMaxSize()}, which can be higher. */ @@ -119,7 +114,10 @@ public abstract class WasmMemory extends EmbedderDataHolder implements TruffleOb */ protected final boolean shared; + @TruffleBoundary protected WasmMemory(long declaredMinSize, long declaredMaxSize, long initialSize, long maxAllowedSize, boolean indexType64, boolean shared) { + assertUnsignedLongLessOrEqual(initialSize, maxAllowedSize, Failure.MEMORY_SIZE_LIMIT_EXCEEDED, "Initial memory size exceeds implementation limit"); + assert compareUnsigned(declaredMinSize, initialSize) <= 0; assert compareUnsigned(initialSize, maxAllowedSize) <= 0; assert compareUnsigned(maxAllowedSize, declaredMaxSize) <= 0; @@ -136,17 +134,6 @@ protected WasmMemory(long declaredMinSize, long declaredMaxSize, long initialSiz this.shared = shared; } - /** - * The current size of this memory instance (measured in number of {@link Sizes#MEMORY_PAGE_SIZE - * pages}). - */ - public abstract long size(); - - /** - * The current size of this memory instance (measured in bytes). - */ - public abstract long byteSize(); - /** * The minimum size of this memory as declared in the binary (measured in number of * {@link Sizes#MEMORY_PAGE_SIZE pages}). @@ -172,7 +159,8 @@ public final long declaredMaxSize() { /** * The current minimum size of the memory (measured in number of {@link Sizes#MEMORY_PAGE_SIZE - * pages}). The size can change based on calls to {@link #grow(long)}. + * pages}). The size can change based on calls to + * {@link WasmMemoryLibrary#grow(WasmMemory,long)}. *

* This is a lower bound on this memory's size. This memory can only be imported with a lower or * equal minimum size. @@ -199,258 +187,10 @@ public final boolean isShared() { return shared; } - /** - * Increases the size of the memory by the specified number of pages. - * - * @return The previous size of the memory if successful, otherwise {@code -1}. - */ - public abstract long grow(long extraPageSize); - - /** - * Shrinks this memory's size to its {@link #declaredMinSize()} initial size}, and sets all - * bytes to 0. - *

- * Note: this does not restore content from data section. For this, use - * {@link org.graalvm.wasm.parser.bytecode.BytecodeParser#resetMemoryState}. - */ - public abstract void reset(); - - // Checkstyle: stop - public abstract int load_i32(Node node, long address); - - public abstract long load_i64(Node node, long address); - - public abstract float load_f32(Node node, long address); - - public abstract double load_f64(Node node, long address); - - public abstract int load_i32_8s(Node node, long address); - - public abstract int load_i32_8u(Node node, long address); - - public abstract int load_i32_16s(Node node, long address); - - public abstract int load_i32_16u(Node node, long address); - - public abstract long load_i64_8s(Node node, long address); - - public abstract long load_i64_8u(Node node, long address); - - public abstract long load_i64_16s(Node node, long address); - - public abstract long load_i64_16u(Node node, long address); - - public abstract long load_i64_32s(Node node, long address); - - public abstract long load_i64_32u(Node node, long address); - - public abstract Vector128 load_i128(Node node, long address); - - public abstract void store_i32(Node node, long address, int value); - - public abstract void store_i64(Node node, long address, long value); - - public abstract void store_f32(Node node, long address, float value); - - public abstract void store_f64(Node node, long address, double value); - - public abstract void store_i32_8(Node node, long address, byte value); - - public abstract void store_i32_16(Node node, long address, short value); - - public abstract void store_i64_8(Node node, long address, byte value); - - public abstract void store_i64_16(Node node, long address, short value); - - public abstract void store_i64_32(Node node, long address, int value); - - public abstract void store_i128(Node node, long address, Vector128 value); - - public abstract int atomic_load_i32(Node node, long address); - - public abstract long atomic_load_i64(Node node, long address); - - public abstract int atomic_load_i32_8u(Node node, long address); - - public abstract int atomic_load_i32_16u(Node node, long address); - - public abstract long atomic_load_i64_8u(Node node, long address); - - public abstract long atomic_load_i64_16u(Node node, long address); - - public abstract long atomic_load_i64_32u(Node node, long address); - - public abstract void atomic_store_i32(Node node, long address, int value); - - public abstract void atomic_store_i64(Node node, long address, long value); - - public abstract void atomic_store_i32_8(Node node, long address, byte value); - - public abstract void atomic_store_i32_16(Node node, long address, short value); - - public abstract void atomic_store_i64_8(Node node, long address, byte value); - - public abstract void atomic_store_i64_16(Node node, long address, short value); - - public abstract void atomic_store_i64_32(Node node, long address, int value); - - public abstract int atomic_rmw_add_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_add_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_add_i32(Node node, long address, int value); - - public abstract long atomic_rmw_add_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_add_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_add_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_add_i64(Node node, long address, long value); - - public abstract int atomic_rmw_sub_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_sub_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_sub_i32(Node node, long address, int value); - - public abstract long atomic_rmw_sub_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_sub_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_sub_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_sub_i64(Node node, long address, long value); - - public abstract int atomic_rmw_and_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_and_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_and_i32(Node node, long address, int value); - - public abstract long atomic_rmw_and_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_and_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_and_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_and_i64(Node node, long address, long value); - - public abstract int atomic_rmw_or_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_or_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_or_i32(Node node, long address, int value); - - public abstract long atomic_rmw_or_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_or_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_or_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_or_i64(Node node, long address, long value); - - public abstract int atomic_rmw_xor_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_xor_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_xor_i32(Node node, long address, int value); - - public abstract long atomic_rmw_xor_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_xor_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_xor_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_xor_i64(Node node, long address, long value); - - public abstract int atomic_rmw_xchg_i32_8u(Node node, long address, byte value); - - public abstract int atomic_rmw_xchg_i32_16u(Node node, long address, short value); - - public abstract int atomic_rmw_xchg_i32(Node node, long address, int value); - - public abstract long atomic_rmw_xchg_i64_8u(Node node, long address, byte value); - - public abstract long atomic_rmw_xchg_i64_16u(Node node, long address, short value); - - public abstract long atomic_rmw_xchg_i64_32u(Node node, long address, int value); - - public abstract long atomic_rmw_xchg_i64(Node node, long address, long value); - - public abstract int atomic_rmw_cmpxchg_i32_8u(Node node, long address, byte expected, byte replacement); - - public abstract int atomic_rmw_cmpxchg_i32_16u(Node node, long address, short expected, short replacement); - - public abstract int atomic_rmw_cmpxchg_i32(Node node, long address, int expected, int replacement); - - public abstract long atomic_rmw_cmpxchg_i64_8u(Node node, long address, byte expected, byte replacement); - - public abstract long atomic_rmw_cmpxchg_i64_16u(Node node, long address, short expected, short replacement); - - public abstract long atomic_rmw_cmpxchg_i64_32u(Node node, long address, int expected, int replacement); - - public abstract long atomic_rmw_cmpxchg_i64(Node node, long address, long expected, long replacement); - - public abstract int atomic_notify(Node node, long address, int count); - - public abstract int atomic_wait32(Node node, long address, int expected, long timeout); - - public abstract int atomic_wait64(Node node, long address, long expected, long timeout); - // Checkstyle: resume - - public abstract WasmMemory duplicate(); - - /** - * Initializes the content of a byte array based memory with the given data instance. - * - * @param source The source data instance that should be copied to the memory - * @param sourceOffset The offset in the source data segment - * @param destinationOffset The offset in the memory - * @param length The number of bytes that should be copied - * - * @throws UnsupportedOperationException If this method is called on an unsafe wasm memory. - */ - public abstract void initialize(byte[] source, int sourceOffset, long destinationOffset, int length); - - /** - * Initializes the content of an unsafe wasm memory with the given date instance. - * - * @param sourceAddress The address of the memory portion that should be copied to the memory - * @param sourceOffset The offset from the data instance address - * @param destinationOffset The offset in the memory - * @param length The number of bytes that should be copied - * - * @throws UnsupportedOperationException If the method is called on a byte array based memory - */ - @TruffleBoundary - public void initializeUnsafe(long sourceAddress, int sourceOffset, long destinationOffset, int length) { - throw new UnsupportedOperationException(); - } - - /** - * Fills the memory with the given value. - * - * @param offset The offset in the memory - * @param length The number of bytes that should be filled - * @param value The value that should be used for filling the memory - */ - public abstract void fill(long offset, long length, byte value); - - /** - * Copies data from another memory into this memory. - * - * @param source The source memory - * @param sourceOffset The offset in the source memory - * @param destinationOffset The offset in this memory - * @param length The number of bytes that should be copied - */ - public abstract void copyFrom(WasmMemory source, long sourceOffset, long destinationOffset, long length); - @TruffleBoundary protected final WasmException trapOutOfBounds(Node node, long address, int length) { final String message = String.format("%d-byte memory access at address 0x%016X (%d) is out-of-bounds (memory size %d bytes).", - length, address, address, byteSize()); + length, address, address, WasmMemoryLibrary.getUncached().byteSize(this)); return WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS, node, message); } @@ -481,7 +221,7 @@ public String readString(int startOffset, WasmFunctionNode node) { byte currentByte; int offset = startOffset; - while ((currentByte = (byte) load_i32_8u(node, offset)) != 0) { + while ((currentByte = (byte) WasmMemoryLibrary.getUncached().load_i32_8u(this, node, offset)) != 0) { bytes.add(currentByte); ++offset; } @@ -503,7 +243,7 @@ public final String readString(int startOffset, int length, Node node) { ByteArrayList bytes = new ByteArrayList(); for (int i = 0; i < length; ++i) { - bytes.add((byte) load_i32_8u(node, startOffset + i)); + bytes.add((byte) WasmMemoryLibrary.getUncached().load_i32_8u(this, node, startOffset + i)); } return new String(bytes.toArray(), StandardCharsets.UTF_8); @@ -526,7 +266,7 @@ public final int writeString(Node node, String string, int offset, int length) { final byte[] bytes = string.getBytes(StandardCharsets.UTF_8); int i = 0; for (; i < bytes.length && i < length; ++i) { - store_i32_8(node, offset + i, bytes[i]); + WasmMemoryLibrary.getUncached().store_i32_8(this, node, offset + i, bytes[i]); } return i; } @@ -549,13 +289,13 @@ public static int encodedStringLength(String string) { long[] view(int address, int length) { long[] chunk = new long[length / 8]; for (int p = address; p < address + length; p += 8) { - chunk[(p - address) / 8] = load_i64(null, p); + chunk[(p - address) / 8] = WasmMemoryLibrary.getUncached().load_i64(this, null, p); } return chunk; } String viewByte(int address) { - final int value = load_i32_8u(null, address); + final int value = WasmMemoryLibrary.getUncached().load_i32_8u(this, null, address); String result = Integer.toHexString(value); if (result.length() == 1) { result = "0" + result; @@ -607,12 +347,12 @@ final boolean hasBufferElements() { } @ExportMessage - final long getBufferSize() { - return byteSize(); + final long getBufferSize(@CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) { + return wasmMemoryLibrary.byteSize(this); } - private void checkOffset(Node node, long byteOffset, int opLength, InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - if (opLength < 0 || byteOffset < 0 || getBufferSize() - opLength < byteOffset) { + private void checkOffset(Node node, WasmMemoryLibrary wasmMemoryLibrary, long byteOffset, int opLength, InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { + if (opLength < 0 || byteOffset < 0 || getBufferSize(wasmMemoryLibrary) - opLength < byteOffset) { errorBranch.enter(node); throw InvalidBufferOffsetException.create(byteOffset, opLength); } @@ -621,25 +361,28 @@ private void checkOffset(Node node, long byteOffset, int opLength, InlinedBranch @ExportMessage final void readBuffer(long byteOffset, byte[] destination, int destinationOffset, int length, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, length, errorBranch); - copyToBuffer(node, destination, byteOffset, destinationOffset, length); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, length, errorBranch); + wasmMemoryLibrary.copyToBuffer(this, node, destination, byteOffset, destinationOffset, length); } @ExportMessage final byte readBufferByte(long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Byte.BYTES, errorBranch); - return (byte) load_i32_8s(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Byte.BYTES, errorBranch); + return (byte) wasmMemoryLibrary.load_i32_8s(this, null, byteOffset); } @ExportMessage final short readBufferShort(ByteOrder order, long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Short.BYTES, errorBranch); - short result = (short) load_i32_16s(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Short.BYTES, errorBranch); + short result = (short) wasmMemoryLibrary.load_i32_16s(this, null, byteOffset); if (order == ByteOrder.BIG_ENDIAN) { result = Short.reverseBytes(result); } @@ -649,9 +392,10 @@ final short readBufferShort(ByteOrder order, long byteOffset, @ExportMessage final int readBufferInt(ByteOrder order, long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Integer.BYTES, errorBranch); - int result = load_i32(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Integer.BYTES, errorBranch); + int result = wasmMemoryLibrary.load_i32(this, null, byteOffset); if (order == ByteOrder.BIG_ENDIAN) { result = Integer.reverseBytes(result); } @@ -661,9 +405,10 @@ final int readBufferInt(ByteOrder order, long byteOffset, @ExportMessage final long readBufferLong(ByteOrder order, long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Long.BYTES, errorBranch); - long result = load_i64(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Long.BYTES, errorBranch); + long result = wasmMemoryLibrary.load_i64(this, null, byteOffset); if (order == ByteOrder.BIG_ENDIAN) { result = Long.reverseBytes(result); } @@ -673,9 +418,10 @@ final long readBufferLong(ByteOrder order, long byteOffset, @ExportMessage final float readBufferFloat(ByteOrder order, long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Float.BYTES, errorBranch); - float result = load_f32(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Float.BYTES, errorBranch); + float result = wasmMemoryLibrary.load_f32(this, null, byteOffset); if (order == ByteOrder.BIG_ENDIAN) { result = Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(result))); } @@ -685,9 +431,10 @@ final float readBufferFloat(ByteOrder order, long byteOffset, @ExportMessage final double readBufferDouble(ByteOrder order, long byteOffset, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Double.BYTES, errorBranch); - double result = load_f64(null, byteOffset); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Double.BYTES, errorBranch); + double result = wasmMemoryLibrary.load_f64(this, null, byteOffset); if (order == ByteOrder.BIG_ENDIAN) { result = Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(result))); } @@ -703,54 +450,60 @@ final boolean isBufferWritable() { @ExportMessage final void writeBufferByte(long byteOffset, byte value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Byte.BYTES, errorBranch); - store_i32_8(null, byteOffset, value); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Byte.BYTES, errorBranch); + wasmMemoryLibrary.store_i32_8(this, null, byteOffset, value); } @ExportMessage final void writeBufferShort(ByteOrder order, long byteOffset, short value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Short.BYTES, errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Short.BYTES, errorBranch); short actualValue = (order == ByteOrder.LITTLE_ENDIAN) ? value : Short.reverseBytes(value); - store_i32_16(null, byteOffset, actualValue); + wasmMemoryLibrary.store_i32_16(this, null, byteOffset, actualValue); } @ExportMessage final void writeBufferInt(ByteOrder order, long byteOffset, int value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Integer.BYTES, errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Integer.BYTES, errorBranch); int actualValue = (order == ByteOrder.LITTLE_ENDIAN) ? value : Integer.reverseBytes(value); - store_i32(null, byteOffset, actualValue); + wasmMemoryLibrary.store_i32(this, null, byteOffset, actualValue); } @ExportMessage final void writeBufferLong(ByteOrder order, long byteOffset, long value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Long.BYTES, errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Long.BYTES, errorBranch); long actualValue = (order == ByteOrder.LITTLE_ENDIAN) ? value : Long.reverseBytes(value); - store_i64(null, byteOffset, actualValue); + wasmMemoryLibrary.store_i64(this, null, byteOffset, actualValue); } @ExportMessage final void writeBufferFloat(ByteOrder order, long byteOffset, float value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Float.BYTES, errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Float.BYTES, errorBranch); float actualValue = (order == ByteOrder.LITTLE_ENDIAN) ? value : Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(value))); - store_f32(null, byteOffset, actualValue); + wasmMemoryLibrary.store_f32(this, null, byteOffset, actualValue); } @ExportMessage final void writeBufferDouble(ByteOrder order, long byteOffset, double value, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidBufferOffsetException { - checkOffset(node, byteOffset, Double.BYTES, errorBranch); + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidBufferOffsetException { + checkOffset(node, wasmMemoryLibrary, byteOffset, Double.BYTES, errorBranch); double actualValue = (order == ByteOrder.LITTLE_ENDIAN) ? value : Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(value))); - store_f64(null, byteOffset, actualValue); + wasmMemoryLibrary.store_f64(this, null, byteOffset, actualValue); } @ExportMessage @@ -759,18 +512,20 @@ boolean hasArrayElements() { } @ExportMessage - long getArraySize() { - return byteSize(); + long getArraySize(@CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) { + return wasmMemoryLibrary.byteSize(this); } @ExportMessage - boolean isArrayElementReadable(long address) { - return address >= 0 && address < getArraySize(); + boolean isArrayElementReadable(long address, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) { + return address >= 0 && address < getArraySize(wasmMemoryLibrary); } @ExportMessage - final boolean isArrayElementModifiable(long address) { - return isArrayElementReadable(address); + final boolean isArrayElementModifiable(long address, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) { + return isArrayElementReadable(address, wasmMemoryLibrary); } @SuppressWarnings({"unused", "static-method"}) @@ -782,21 +537,23 @@ final boolean isArrayElementInsertable(long address) { @ExportMessage public Object readArrayElement(long address, @Bind Node node, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) throws InvalidArrayIndexException { - if (!isArrayElementReadable(address)) { + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidArrayIndexException { + if (!isArrayElementReadable(address, wasmMemoryLibrary)) { errorBranch.enter(node); throw InvalidArrayIndexException.create(address); } - return load_i32_8u(null, address); + return wasmMemoryLibrary.load_i32_8u(this, null, address); } @ExportMessage public void writeArrayElement(long address, Object value, @Bind Node node, @CachedLibrary(limit = "3") InteropLibrary valueLib, - @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch) + @Shared("errorBranch") @Cached InlinedBranchProfile errorBranch, + @CachedLibrary(value = "this") WasmMemoryLibrary wasmMemoryLibrary) throws InvalidArrayIndexException, UnsupportedMessageException, UnsupportedTypeException { - if (!isArrayElementModifiable(address)) { + if (!isArrayElementModifiable(address, wasmMemoryLibrary)) { errorBranch.enter(node); throw InvalidArrayIndexException.create(address); } @@ -807,7 +564,7 @@ public void writeArrayElement(long address, Object value, errorBranch.enter(node); throw UnsupportedTypeException.create(new Object[]{value}, "Only bytes can be stored into WebAssembly memory."); } - store_i32_8(null, address, rawValue); + wasmMemoryLibrary.store_i32_8(this, null, address, rawValue); } protected void invokeGrowCallback() { @@ -822,63 +579,17 @@ protected int invokeWaitCallback(Node node, long address, long expected, long ti return WebAssembly.invokeMemWaitCallback(node, this, address, expected, timeout, is64); } - public abstract void close(); - - public abstract ByteBuffer asByteBuffer(); - public boolean freed() { return true; } - protected boolean outOfBounds(int offset, int length) { - return length < 0 || offset < 0 || offset > getBufferSize() - length; - } - - protected boolean outOfBounds(long offset, long length) { - return length < 0 || offset < 0 || offset > getBufferSize() - length; - } - - public final WasmMemory checkSize(long initialSize) { - if (byteSize() < initialSize * Sizes.MEMORY_PAGE_SIZE) { + public final WasmMemory checkSize(WasmMemoryLibrary memoryLib, long initialSize) { + if (memoryLib.byteSize(this) < initialSize * Sizes.MEMORY_PAGE_SIZE) { throw CompilerDirectives.shouldNotReachHere("Memory size must not be less than initial size"); } return this; } - /** - * Copy data from an input stream into memory. - * - * @param node the node used for errors - * @param stream the input stream - * @param offset the offset in the memory - * @param length the length of the data - * @return the number of read bytes, -1 if the end of the stream has been reached. - * @throws IOException if reading the stream leads to an error. - */ - public abstract int copyFromStream(Node node, InputStream stream, int offset, int length) throws IOException; - - /** - * Copy data from memory into an output stream. - * - * @param node the node used for errors - * @param stream the output stream - * @param offset the offset in the memory - * @param length the length of the data - * @throws IOException if writing the stream leads to an error. - */ - public abstract void copyToStream(Node node, OutputStream stream, int offset, int length) throws IOException; - - /** - * Copy data from memory into a byte[] array. - * - * @param node the node used for errors - * @param dst the output buffer - * @param srcOffset the offset in the memory - * @param dstOffset the offset in the byte[] array - * @param length the length of the data - */ - public abstract void copyToBuffer(Node node, byte[] dst, long srcOffset, int dstOffset, int length); - public boolean isUnsafe() { return false; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryFactory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryFactory.java index d1796d0e5c50..0364c9592fa1 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryFactory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,39 +40,37 @@ */ package org.graalvm.wasm.memory; -import org.graalvm.wasm.constants.Sizes; import org.graalvm.wasm.exception.Failure; import static org.graalvm.wasm.Assert.assertTrue; public class WasmMemoryFactory { - public static WasmMemory createMemory(long declaredMinSize, long declaredMaxSize, long maxAllowedSize, boolean indexType64, boolean shared, boolean unsafeMemory) { + public static WasmMemory createMemory(long declaredMinSize, long declaredMaxSize, boolean indexType64, boolean shared, boolean unsafeMemory, boolean directByteBufferMemoryAccess) { + if (directByteBufferMemoryAccess) { + assertTrue(unsafeMemory, "DirectByteBufferMemoryAccess is only supported when UseUnsafeMemory flag is set.", Failure.SHARED_MEMORY_WITHOUT_UNSAFE); + } if (shared) { assertTrue(unsafeMemory, "Shared memories are only supported when UseUnsafeMemory flag is set.", Failure.SHARED_MEMORY_WITHOUT_UNSAFE); } if (unsafeMemory) { - if (maxAllowedSize > Sizes.MAX_MEMORY_INSTANCE_SIZE) { - return new NativeWasmMemory(declaredMinSize, declaredMaxSize, maxAllowedSize, indexType64, shared); - } else { - return new UnsafeWasmMemory(declaredMinSize, declaredMaxSize, maxAllowedSize, indexType64, shared); + if (directByteBufferMemoryAccess || shared) { + return new UnsafeWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared); + } else if (declaredMaxSize > ByteArrayWasmMemory.MAX_ALLOWED_SIZE) { + return new NativeWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared); } - } else { - assert maxAllowedSize <= Sizes.MAX_MEMORY_INSTANCE_SIZE; - return new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, maxAllowedSize, indexType64, shared); } + return new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared); } - public static Class getMemoryImplementation(long maxAllowedSize, boolean unsafeMemory) { + public static long getMaximumAllowedSize(boolean shared, boolean unsafeMemory, boolean directByteBufferMemoryAccess) { if (unsafeMemory) { - if (maxAllowedSize > Sizes.MAX_MEMORY_INSTANCE_SIZE) { - return NativeWasmMemory.class; + if (directByteBufferMemoryAccess || shared) { + return UnsafeWasmMemory.MAX_ALLOWED_SIZE; } else { - return UnsafeWasmMemory.class; + return NativeWasmMemory.MAX_ALLOWED_SIZE; } - } else { - assert maxAllowedSize <= Sizes.MAX_MEMORY_INSTANCE_SIZE; - return ByteArrayWasmMemory.class; } + return ByteArrayWasmMemory.MAX_ALLOWED_SIZE; } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryLibrary.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryLibrary.java new file mode 100644 index 000000000000..fa7c7fa55893 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/memory/WasmMemoryLibrary.java @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.memory; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.library.GenerateLibrary; +import com.oracle.truffle.api.library.Library; +import com.oracle.truffle.api.library.LibraryFactory; +import com.oracle.truffle.api.nodes.Node; +import org.graalvm.wasm.api.Vector128; +import org.graalvm.wasm.constants.Sizes; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +@GenerateLibrary(dynamicDispatchEnabled = false, pushEncapsulatingNode = false) +public abstract class WasmMemoryLibrary extends Library { + + private static final LibraryFactory FACTORY = LibraryFactory.resolve(WasmMemoryLibrary.class); + + public static LibraryFactory getFactory() { + return FACTORY; + } + + public static WasmMemoryLibrary getUncached() { + return FACTORY.getUncached(); + } + + /** + * The current size of this memory instance (measured in number of {@link Sizes#MEMORY_PAGE_SIZE + * pages}). + */ + public abstract long size(WasmMemory memory); + + /** + * The current size of this memory instance (measured in bytes). + */ + public abstract long byteSize(WasmMemory memory); + + /** + * Increases the size of the memory by the specified number of pages. + * + * @return The previous size of the memory if successful, otherwise {@code -1}. + */ + public abstract long grow(WasmMemory memory, long extraPageSize); + + /** + * Initializes the content of a byte array based memory with the given data instance. + * + * @param source The source data instance that should be copied to the memory + * @param sourceOffset The offset in the source data segment + * @param destinationOffset The offset in the memory + * @param length The number of bytes that should be copied + * + * @throws UnsupportedOperationException If this method is called on an unsafe wasm memory. + */ + public abstract void initialize(WasmMemory memory, byte[] source, int sourceOffset, long destinationOffset, int length); + + /** + * Initializes the content of an unsafe wasm memory with the given date instance. + * + * @param sourceAddress The address of the memory portion that should be copied to the memory + * @param sourceOffset The offset from the data instance address + * @param destinationOffset The offset in the memory + * @param length The number of bytes that should be copied + * + * @throws UnsupportedOperationException If the method is called on a byte array based memory + */ + @TruffleBoundary + @SuppressWarnings("unused") + public void initializeUnsafe(WasmMemory memory, long sourceAddress, int sourceOffset, long destinationOffset, int length) { + throw new UnsupportedOperationException(); + } + + /** + * Fills the memory with the given value. + * + * @param offset The offset in the memory + * @param length The number of bytes that should be filled + * @param value The value that should be used for filling the memory + */ + public abstract void fill(WasmMemory memory, long offset, long length, byte value); + + /** + * Copies data from another memory into this memory. + * + * @param source The source memory + * @param sourceOffset The offset in the source memory + * @param destinationOffset The offset in this memory + * @param length The number of bytes that should be copied + */ + public abstract void copyFrom(WasmMemory memory, WasmMemory source, long sourceOffset, long destinationOffset, long length); + + /** + * Copy data from an input stream into memory. + * + * @param node the node used for errors + * @param stream the input stream + * @param offset the offset in the memory + * @param length the length of the data + * @return the number of read bytes, -1 if the end of the stream has been reached. + * @throws IOException if reading the stream leads to an error. + */ + public abstract int copyFromStream(WasmMemory memory, Node node, InputStream stream, int offset, int length) throws IOException; + + /** + * Copy data from memory into an output stream. + * + * @param node the node used for errors + * @param stream the output stream + * @param offset the offset in the memory + * @param length the length of the data + * @throws IOException if writing the stream leads to an error. + */ + public abstract void copyToStream(WasmMemory memory, Node node, OutputStream stream, int offset, int length) throws IOException; + + /** + * Copy data from memory into a byte[] array. + * + * @param node the node used for errors + * @param dst the output buffer + * @param srcOffset the offset in the memory + * @param dstOffset the offset in the byte[] array + * @param length the length of the data + */ + public abstract void copyToBuffer(WasmMemory memory, Node node, byte[] dst, long srcOffset, int dstOffset, int length); + + // Checkstyle: stop + public abstract int load_i32(WasmMemory memory, Node node, long address); + + public abstract long load_i64(WasmMemory memory, Node node, long address); + + public abstract float load_f32(WasmMemory memory, Node node, long address); + + public abstract double load_f64(WasmMemory memory, Node node, long address); + + public abstract int load_i32_8s(WasmMemory memory, Node node, long address); + + public abstract int load_i32_8u(WasmMemory memory, Node node, long address); + + public abstract int load_i32_16s(WasmMemory memory, Node node, long address); + + public abstract int load_i32_16u(WasmMemory memory, Node node, long address); + + public abstract long load_i64_8s(WasmMemory memory, Node node, long address); + + public abstract long load_i64_8u(WasmMemory memory, Node node, long address); + + public abstract long load_i64_16s(WasmMemory memory, Node node, long address); + + public abstract long load_i64_16u(WasmMemory memory, Node node, long address); + + public abstract long load_i64_32s(WasmMemory memory, Node node, long address); + + public abstract long load_i64_32u(WasmMemory memory, Node node, long address); + + public abstract Vector128 load_i128(WasmMemory memory, Node node, long address); + + public abstract void store_i32(WasmMemory memory, Node node, long address, int value); + + public abstract void store_i64(WasmMemory memory, Node node, long address, long value); + + public abstract void store_f32(WasmMemory memory, Node node, long address, float value); + + public abstract void store_f64(WasmMemory memory, Node node, long address, double value); + + public abstract void store_i32_8(WasmMemory memory, Node node, long address, byte value); + + public abstract void store_i32_16(WasmMemory memory, Node node, long address, short value); + + public abstract void store_i64_8(WasmMemory memory, Node node, long address, byte value); + + public abstract void store_i64_16(WasmMemory memory, Node node, long address, short value); + + public abstract void store_i64_32(WasmMemory memory, Node node, long address, int value); + + public abstract void store_i128(WasmMemory memory, Node node, long address, Vector128 value); + + public abstract int atomic_load_i32(WasmMemory memory, Node node, long address); + + public abstract long atomic_load_i64(WasmMemory memory, Node node, long address); + + public abstract int atomic_load_i32_8u(WasmMemory memory, Node node, long address); + + public abstract int atomic_load_i32_16u(WasmMemory memory, Node node, long address); + + public abstract long atomic_load_i64_8u(WasmMemory memory, Node node, long address); + + public abstract long atomic_load_i64_16u(WasmMemory memory, Node node, long address); + + public abstract long atomic_load_i64_32u(WasmMemory memory, Node node, long address); + + public abstract void atomic_store_i32(WasmMemory memory, Node node, long address, int value); + + public abstract void atomic_store_i64(WasmMemory memory, Node node, long address, long value); + + public abstract void atomic_store_i32_8(WasmMemory memory, Node node, long address, byte value); + + public abstract void atomic_store_i32_16(WasmMemory memory, Node node, long address, short value); + + public abstract void atomic_store_i64_8(WasmMemory memory, Node node, long address, byte value); + + public abstract void atomic_store_i64_16(WasmMemory memory, Node node, long address, short value); + + public abstract void atomic_store_i64_32(WasmMemory memory, Node node, long address, int value); + + public abstract int atomic_rmw_add_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_add_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_add_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_add_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_add_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_add_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_add_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_sub_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_sub_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_sub_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_sub_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_sub_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_sub_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_sub_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_and_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_and_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_and_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_and_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_and_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_and_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_and_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_or_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_or_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_or_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_or_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_or_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_or_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_or_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_xor_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_xor_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_xor_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_xor_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_xor_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_xor_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_xor_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_xchg_i32_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract int atomic_rmw_xchg_i32_16u(WasmMemory memory, Node node, long address, short value); + + public abstract int atomic_rmw_xchg_i32(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_xchg_i64_8u(WasmMemory memory, Node node, long address, byte value); + + public abstract long atomic_rmw_xchg_i64_16u(WasmMemory memory, Node node, long address, short value); + + public abstract long atomic_rmw_xchg_i64_32u(WasmMemory memory, Node node, long address, int value); + + public abstract long atomic_rmw_xchg_i64(WasmMemory memory, Node node, long address, long value); + + public abstract int atomic_rmw_cmpxchg_i32_8u(WasmMemory memory, Node node, long address, byte expected, byte replacement); + + public abstract int atomic_rmw_cmpxchg_i32_16u(WasmMemory memory, Node node, long address, short expected, short replacement); + + public abstract int atomic_rmw_cmpxchg_i32(WasmMemory memory, Node node, long address, int expected, int replacement); + + public abstract long atomic_rmw_cmpxchg_i64_8u(WasmMemory memory, Node node, long address, byte expected, byte replacement); + + public abstract long atomic_rmw_cmpxchg_i64_16u(WasmMemory memory, Node node, long address, short expected, short replacement); + + public abstract long atomic_rmw_cmpxchg_i64_32u(WasmMemory memory, Node node, long address, int expected, int replacement); + + public abstract long atomic_rmw_cmpxchg_i64(WasmMemory memory, Node node, long address, long expected, long replacement); + + public abstract int atomic_notify(WasmMemory memory, Node node, long address, int count); + + public abstract int atomic_wait32(WasmMemory memory, Node node, long address, int expected, long timeout); + + public abstract int atomic_wait64(WasmMemory memory, Node node, long address, long expected, long timeout); + // Checkstyle: resume + + public abstract void close(WasmMemory memory); + + /** + * Shrinks this memory's size to its {@link WasmMemory#declaredMinSize()} initial size}, and + * sets all bytes to 0. + *

+ * Note: this does not restore content from data section. For this, use + * {@link org.graalvm.wasm.parser.bytecode.BytecodeParser#resetMemoryState}. + */ + public abstract void reset(WasmMemory memory); + + @SuppressWarnings("unused") + public ByteBuffer asByteBuffer(WasmMemory memory) { + return null; + } + + public abstract WasmMemory duplicate(WasmMemory memory); +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFixedMemoryImplFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFixedMemoryImplFunctionNode.java new file mode 100644 index 000000000000..0ccf54292d55 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFixedMemoryImplFunctionNode.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.nodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Idempotent; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; +import org.graalvm.wasm.WasmCodeEntry; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmModule; +import org.graalvm.wasm.memory.WasmMemoryLibrary; + +import java.util.Arrays; + +/** + * Dispatches to specialized instances of {@link WasmInstrumentableFunctionNode}, ensuring that each + * {@link WasmInstrumentableFunctionNode} sees only one implementation of {@link WasmMemoryLibrary} + * for each memory, meaning that all memory accesses are monomorphic in the compiled + * {@link WasmFunctionNode}. If a cache limit is exceeded (too many combinations of memory + * implementations), a {@link WasmInstrumentableFunctionNode} using dispatched libraries for each + * memory will be used instead. + */ +public abstract class WasmFixedMemoryImplFunctionNode extends Node { + + private final WasmModule module; + private final WasmCodeEntry codeEntry; + private final int bytecodeStartOffset; + private final int bytecodeEndOffset; + private final Node[] callNodes; + + private static final WasmInstrumentableFunctionNode[] EMPTY_INSTRUMENTABLE_FUNCTION_NODES = new WasmInstrumentableFunctionNode[0]; + + @Children private WasmInstrumentableFunctionNode[] instrumentableFunctionNodes = EMPTY_INSTRUMENTABLE_FUNCTION_NODES; + + protected WasmFixedMemoryImplFunctionNode(WasmModule module, WasmCodeEntry codeEntry, int bytecodeStartOffset, int bytecodeEndOffset, Node[] callNodes) { + this.module = module; + this.codeEntry = codeEntry; + this.bytecodeStartOffset = bytecodeStartOffset; + this.bytecodeEndOffset = bytecodeEndOffset; + this.callNodes = callNodes; + } + + public static WasmFixedMemoryImplFunctionNode create(WasmModule module, WasmCodeEntry codeEntry, int bytecodeStartOffset, int bytecodeEndOffset, Node[] callNodes) { + return WasmFixedMemoryImplFunctionNodeGen.create(module, codeEntry, bytecodeStartOffset, bytecodeEndOffset, callNodes); + } + + @Specialization(guards = {"memoryCount() == 1"}, limit = "3") + protected void doFixedMemoryImpl(VirtualFrame frame, WasmContext context, WasmInstance instance, + @CachedLibrary(value = "instance.memory(0)") @SuppressWarnings("unused") WasmMemoryLibrary cachedMemoryLib0, + @Cached("createMemoryLibs1(cachedMemoryLib0)") @SuppressWarnings("unused") WasmMemoryLibrary[] cachedMemoryLibs, + @Cached(value = "createSpecializedFunctionNode(cachedMemoryLibs)", adopt = false) WasmInstrumentableFunctionNode specializedFunctionNode) { + specializedFunctionNode.execute(frame, context, instance); + } + + @Specialization(replaces = "doFixedMemoryImpl") + protected void doDispatched(VirtualFrame frame, WasmContext context, WasmInstance instance, + @Cached(value = "createDispatchedFunctionNode()", adopt = false) WasmInstrumentableFunctionNode dispatchedFunctionNode) { + dispatchedFunctionNode.execute(frame, context, instance); + } + + @NeverDefault + protected WasmMemoryLibrary[] createMemoryLibs1(WasmMemoryLibrary memoryLibs) { + return new WasmMemoryLibrary[]{memoryLibs}; + } + + @Idempotent + protected int memoryCount() { + return module.memoryCount(); + } + + @NeverDefault + protected WasmInstrumentableFunctionNode createSpecializedFunctionNode(WasmMemoryLibrary[] memoryLibs) { + CompilerAsserts.neverPartOfCompilation(); + WasmInstrumentableFunctionNode instrumentableFunctionNode = new WasmInstrumentableFunctionNode(module, codeEntry, bytecodeStartOffset, bytecodeEndOffset, callNodes, memoryLibs); + instrumentableFunctionNodes = Arrays.copyOf(instrumentableFunctionNodes, instrumentableFunctionNodes.length + 1); + instrumentableFunctionNodes[instrumentableFunctionNodes.length - 1] = insert(instrumentableFunctionNode); + notifyInserted(instrumentableFunctionNode); + return instrumentableFunctionNode; + } + + @NeverDefault + protected WasmInstrumentableFunctionNode createDispatchedFunctionNode() { + CompilerAsserts.neverPartOfCompilation(); + WasmMemoryLibrary[] memoryLibs = new WasmMemoryLibrary[module.memoryCount()]; + for (int memoryIndex = 0; memoryIndex < module.memoryCount(); memoryIndex++) { + memoryLibs[memoryIndex] = insert(WasmMemoryLibrary.getFactory().createDispatched(3)); + } + WasmInstrumentableFunctionNode instrumentableFunctionNode = new WasmInstrumentableFunctionNode(module, codeEntry, bytecodeStartOffset, bytecodeEndOffset, callNodes, memoryLibs); + instrumentableFunctionNodes = new WasmInstrumentableFunctionNode[]{insert(instrumentableFunctionNode)}; + notifyInserted(instrumentableFunctionNode); + return instrumentableFunctionNode; + } + + public abstract void execute(VirtualFrame frame, WasmContext context, WasmInstance instance); +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java index 96bdfaf4beab..df9f5b4f72ef 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -104,6 +104,7 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** * This node represents the function body of a WebAssembly function. It executes the instruction @@ -153,22 +154,19 @@ public final class WasmFunctionNode extends Node implements BytecodeOSRNode { @CompilationFinal(dimensions = 1) private byte[] bytecode; @CompilationFinal private WasmNotifyFunction notifyFunction; - public WasmFunctionNode(WasmModule module, WasmCodeEntry codeEntry, int bytecodeStartOffset, int bytecodeEndOffset) { + @Children private WasmMemoryLibrary[] memoryLibs; + + public WasmFunctionNode(WasmModule module, WasmCodeEntry codeEntry, int bytecodeStartOffset, int bytecodeEndOffset, Node[] callNodes, WasmMemoryLibrary[] memoryLibs) { this.module = module; this.codeEntry = codeEntry; this.bytecodeStartOffset = bytecodeStartOffset; this.bytecodeEndOffset = bytecodeEndOffset; this.bytecode = codeEntry.bytecode(); - } - - @SuppressWarnings("hiding") - public void initializeCallNodes(Node[] callNodes) { - assert this.callNodes == null; - this.callNodes = callNodes; - } - - public int startOffset() { - return bytecodeStartOffset; + this.callNodes = new Node[callNodes.length]; + for (int childIndex = 0; childIndex < callNodes.length; childIndex++) { + this.callNodes[childIndex] = insert(callNodes[childIndex].deepCopy()); + } + this.memoryLibs = memoryLibs; } private void enterErrorBranch() { @@ -183,12 +181,12 @@ void updateBytecode(byte[] bytecode, int bytecodeStartOffset, int bytecodeEndOff this.notifyFunction = notifyFunction; } - private WasmMemory memory0(WasmInstance instance) { - return memory(instance, 0).checkSize(module.memoryInitialSize(0)); + private WasmMemory memory(WasmInstance instance, int index) { + return instance.memory(index).checkSize(memoryLib(index), module.memoryInitialSize(index)); } - private WasmMemory memory(WasmInstance instance, int index) { - return module.memory(instance, index); + private WasmMemoryLibrary memoryLib(int memoryIndex) { + return memoryLibs[memoryIndex]; } // region OSR support @@ -270,7 +268,8 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, int line = startLine; // Note: The module may not have any memories. - final WasmMemory zeroMemory = !codeEntry.usesMemoryZero() ? null : memory0(instance); + final WasmMemory zeroMemory = !codeEntry.usesMemoryZero() ? null : memory(instance, 0); + final WasmMemoryLibrary zeroMemoryLib = !codeEntry.usesMemoryZero() ? null : memoryLib(0); check(bytecode.length, (1 << 31) - 1); @@ -808,7 +807,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - load(memory, frame, stackPointer - 1, opcode, address); + load(memory, memoryLib(memoryIndex), frame, stackPointer - 1, opcode, address); break; } case Bytecode.I32_LOAD_U8: { @@ -818,7 +817,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, int baseAddress = popInt(frame, stackPointer - 1); final long address = effectiveMemoryAddress(memOffset, baseAddress); - int value = zeroMemory.load_i32(this, address); + int value = zeroMemoryLib.load_i32(zeroMemory, this, address); pushInt(frame, stackPointer - 1, value); break; } @@ -829,7 +828,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, int baseAddress = popInt(frame, stackPointer - 1); final long address = effectiveMemoryAddress(memOffset, baseAddress); - int value = zeroMemory.load_i32(this, address); + int value = zeroMemoryLib.load_i32(zeroMemory, this, address); pushInt(frame, stackPointer - 1, value); break; } @@ -852,7 +851,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int baseAddress = popInt(frame, stackPointer - 1); final long address = effectiveMemoryAddress(memOffset, baseAddress); - load(zeroMemory, frame, stackPointer - 1, opcode, address); + load(zeroMemory, zeroMemoryLib, frame, stackPointer - 1, opcode, address); break; } case Bytecode.I64_LOAD_I32: @@ -874,7 +873,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int baseAddress = popInt(frame, stackPointer - 1); final long address = effectiveMemoryAddress(memOffset, baseAddress); - load(zeroMemory, frame, stackPointer - 1, opcode, address); + load(zeroMemory, zeroMemoryLib, frame, stackPointer - 1, opcode, address); break; } case Bytecode.I32_STORE: @@ -917,7 +916,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - store(memory, frame, stackPointer - 1, opcode, address); + store(memory, memoryLib(memoryIndex), frame, stackPointer - 1, opcode, address); stackPointer -= 2; break; } @@ -929,7 +928,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final long address = effectiveMemoryAddress(memOffset, baseAddress); final int value = popInt(frame, stackPointer - 1); - zeroMemory.store_i32(this, address, value); + zeroMemoryLib.store_i32(zeroMemory, this, address, value); stackPointer -= 2; break; } @@ -941,7 +940,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final long address = effectiveMemoryAddress(memOffset, baseAddress); final int value = popInt(frame, stackPointer - 1); - zeroMemory.store_i32(this, address, value); + zeroMemoryLib.store_i32(zeroMemory, this, address, value); stackPointer -= 2; break; } @@ -959,7 +958,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int baseAddress = popInt(frame, stackPointer - 2); final long address = effectiveMemoryAddress(memOffset, baseAddress); - store(zeroMemory, frame, stackPointer - 1, opcode, address); + store(zeroMemory, zeroMemoryLib, frame, stackPointer - 1, opcode, address); stackPointer -= 2; break; @@ -978,7 +977,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int baseAddress = popInt(frame, stackPointer - 2); final long address = effectiveMemoryAddress(memOffset, baseAddress); - store(zeroMemory, frame, stackPointer - 1, opcode, address); + store(zeroMemory, zeroMemoryLib, frame, stackPointer - 1, opcode, address); stackPointer -= 2; break; @@ -987,7 +986,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int memoryIndex = rawPeekI32(bytecode, offset); offset += 4; final WasmMemory memory = memory(instance, memoryIndex); - int pageSize = (int) memory.size(); + int pageSize = (int) memoryLib(memoryIndex).size(memory); pushInt(frame, stackPointer, pageSize); stackPointer++; break; @@ -997,7 +996,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, offset += 4; final WasmMemory memory = memory(instance, memoryIndex); int extraSize = popInt(frame, stackPointer - 1); - int previousSize = (int) memory.grow(extraSize); + int previousSize = (int) memoryLib(memoryIndex).grow(memory, extraSize); pushInt(frame, stackPointer - 1, previousSize); break; } @@ -1671,7 +1670,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, final int memoryIndex = rawPeekI32(bytecode, offset); offset += 4; final WasmMemory memory = memory(instance, memoryIndex); - long pageSize = memory.size(); + long pageSize = memoryLib(memoryIndex).size(memory); pushLong(frame, stackPointer, pageSize); stackPointer++; break; @@ -1681,7 +1680,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, offset += 4; final WasmMemory memory = memory(instance, memoryIndex); long extraSize = popLong(frame, stackPointer - 1); - long previousSize = memory.grow(extraSize); + long previousSize = memoryLib(memoryIndex).grow(memory, extraSize); pushLong(frame, stackPointer - 1, previousSize); break; } @@ -1713,7 +1712,7 @@ public Object executeBodyFromOffset(WasmContext context, WasmInstance instance, } final WasmMemory memory = memory(instance, memoryIndex); - final int stackPointerDecrement = executeAtomic(frame, stackPointer, atomicOpcode, memory, memOffset, indexType64); + final int stackPointerDecrement = executeAtomic(frame, stackPointer, atomicOpcode, memory, memoryLib(memoryIndex), memOffset, indexType64); stackPointer -= stackPointerDecrement; break; } @@ -1820,103 +1819,103 @@ private long effectiveMemoryAddress64(long staticAddressOffset, long dynamicAddr } } - private void load(WasmMemory memory, VirtualFrame frame, int stackPointer, int opcode, long address) { + private void load(WasmMemory memory, WasmMemoryLibrary memoryLib, VirtualFrame frame, int stackPointer, int opcode, long address) { switch (opcode) { case Bytecode.I32_LOAD: case Bytecode.I32_LOAD_U8: case Bytecode.I32_LOAD_I32: { - final int value = memory.load_i32(this, address); + final int value = memoryLib.load_i32(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.I64_LOAD: case Bytecode.I64_LOAD_U8: case Bytecode.I64_LOAD_I32: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.F32_LOAD: case Bytecode.F32_LOAD_U8: case Bytecode.F32_LOAD_I32: { - final float value = memory.load_f32(this, address); + final float value = memoryLib.load_f32(memory, this, address); pushFloat(frame, stackPointer, value); break; } case Bytecode.F64_LOAD: case Bytecode.F64_LOAD_U8: case Bytecode.F64_LOAD_I32: { - final double value = memory.load_f64(this, address); + final double value = memoryLib.load_f64(memory, this, address); pushDouble(frame, stackPointer, value); break; } case Bytecode.I32_LOAD8_S: case Bytecode.I32_LOAD8_S_U8: case Bytecode.I32_LOAD8_S_I32: { - final int value = memory.load_i32_8s(this, address); + final int value = memoryLib.load_i32_8s(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.I32_LOAD8_U: case Bytecode.I32_LOAD8_U_U8: case Bytecode.I32_LOAD8_U_I32: { - final int value = memory.load_i32_8u(this, address); + final int value = memoryLib.load_i32_8u(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.I32_LOAD16_S: case Bytecode.I32_LOAD16_S_U8: case Bytecode.I32_LOAD16_S_I32: { - final int value = memory.load_i32_16s(this, address); + final int value = memoryLib.load_i32_16s(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.I32_LOAD16_U: case Bytecode.I32_LOAD16_U_U8: case Bytecode.I32_LOAD16_U_I32: { - final int value = memory.load_i32_16u(this, address); + final int value = memoryLib.load_i32_16u(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.I64_LOAD8_S: case Bytecode.I64_LOAD8_S_U8: case Bytecode.I64_LOAD8_S_I32: { - final long value = memory.load_i64_8s(this, address); + final long value = memoryLib.load_i64_8s(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.I64_LOAD8_U: case Bytecode.I64_LOAD8_U_U8: case Bytecode.I64_LOAD8_U_I32: { - final long value = memory.load_i64_8u(this, address); + final long value = memoryLib.load_i64_8u(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.I64_LOAD16_S: case Bytecode.I64_LOAD16_S_U8: case Bytecode.I64_LOAD16_S_I32: { - final long value = memory.load_i64_16s(this, address); + final long value = memoryLib.load_i64_16s(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.I64_LOAD16_U: case Bytecode.I64_LOAD16_U_U8: case Bytecode.I64_LOAD16_U_I32: { - final long value = memory.load_i64_16u(this, address); + final long value = memoryLib.load_i64_16u(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.I64_LOAD32_S: case Bytecode.I64_LOAD32_S_U8: case Bytecode.I64_LOAD32_S_I32: { - final long value = memory.load_i64_32s(this, address); + final long value = memoryLib.load_i64_32s(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.I64_LOAD32_U: case Bytecode.I64_LOAD32_U_U8: case Bytecode.I64_LOAD32_U_I32: { - final long value = memory.load_i64_32u(this, address); + final long value = memoryLib.load_i64_32u(memory, this, address); pushLong(frame, stackPointer, value); break; } @@ -1925,69 +1924,69 @@ private void load(WasmMemory memory, VirtualFrame frame, int stackPointer, int o } } - private void store(WasmMemory memory, VirtualFrame frame, int stackPointer, int opcode, long address) { + private void store(WasmMemory memory, WasmMemoryLibrary memoryLib, VirtualFrame frame, int stackPointer, int opcode, long address) { switch (opcode) { case Bytecode.I32_STORE: case Bytecode.I32_STORE_U8: case Bytecode.I32_STORE_I32: { final int value = popInt(frame, stackPointer); - memory.store_i32(this, address, value); + memoryLib.store_i32(memory, this, address, value); break; } case Bytecode.I64_STORE: case Bytecode.I64_STORE_U8: case Bytecode.I64_STORE_I32: { final long value = popLong(frame, stackPointer); - memory.store_i64(this, address, value); + memoryLib.store_i64(memory, this, address, value); break; } case Bytecode.F32_STORE: case Bytecode.F32_STORE_U8: case Bytecode.F32_STORE_I32: { final float value = popFloat(frame, stackPointer); - memory.store_f32(this, address, value); + memoryLib.store_f32(memory, this, address, value); break; } case Bytecode.F64_STORE: case Bytecode.F64_STORE_U8: case Bytecode.F64_STORE_I32: { final double value = popDouble(frame, stackPointer); - memory.store_f64(this, address, value); + memoryLib.store_f64(memory, this, address, value); break; } case Bytecode.I32_STORE_8: case Bytecode.I32_STORE_8_U8: case Bytecode.I32_STORE_8_I32: { final int value = popInt(frame, stackPointer); - memory.store_i32_8(this, address, (byte) value); + memoryLib.store_i32_8(memory, this, address, (byte) value); break; } case Bytecode.I32_STORE_16: case Bytecode.I32_STORE_16_U8: case Bytecode.I32_STORE_16_I32: { final int value = popInt(frame, stackPointer); - memory.store_i32_16(this, address, (short) value); + memoryLib.store_i32_16(memory, this, address, (short) value); break; } case Bytecode.I64_STORE_8: case Bytecode.I64_STORE_8_U8: case Bytecode.I64_STORE_8_I32: { final long value = popLong(frame, stackPointer); - memory.store_i64_8(this, address, (byte) value); + memoryLib.store_i64_8(memory, this, address, (byte) value); break; } case Bytecode.I64_STORE_16: case Bytecode.I64_STORE_16_U8: case Bytecode.I64_STORE_16_I32: { final long value = popLong(frame, stackPointer); - memory.store_i64_16(this, address, (short) value); + memoryLib.store_i64_16(memory, this, address, (short) value); break; } case Bytecode.I64_STORE_32: case Bytecode.I64_STORE_32_U8: case Bytecode.I64_STORE_32_I32: { final long value = popLong(frame, stackPointer); - memory.store_i64_32(this, address, (int) value); + memoryLib.store_i64_32(memory, this, address, (int) value); break; } default: @@ -2091,7 +2090,7 @@ private void executeMemoryFill(WasmInstance instance, VirtualFrame frame, int st memory_fill(instance, n, val, dst, memoryIndex); } - private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, WasmMemory memory, long memOffset, int indexType64) { + private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, WasmMemory memory, WasmMemoryLibrary memoryLib, long memOffset, int indexType64) { switch (opcode) { case Bytecode.ATOMIC_NOTIFY: case Bytecode.ATOMIC_I32_RMW_ADD: @@ -2143,7 +2142,7 @@ private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, Wasm baseAddress = popLong(frame, stackPointer - 2); } final long address = effectiveMemoryAddress64(memOffset, baseAddress); - executeAtomicAtAddress(memory, frame, stackPointer - 1, opcode, address); + executeAtomicAtAddress(memory, memoryLib, frame, stackPointer - 1, opcode, address); return 1; } case Bytecode.ATOMIC_WAIT32: @@ -2162,7 +2161,7 @@ private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, Wasm baseAddress = popLong(frame, stackPointer - 3); } final long address = effectiveMemoryAddress64(memOffset, baseAddress); - executeAtomicAtAddress(memory, frame, stackPointer - 1, opcode, address); + executeAtomicAtAddress(memory, memoryLib, frame, stackPointer - 1, opcode, address); return 2; } case Bytecode.ATOMIC_I32_LOAD: @@ -2179,7 +2178,7 @@ private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, Wasm baseAddress = popLong(frame, stackPointer - 1); } final long address = effectiveMemoryAddress64(memOffset, baseAddress); - executeAtomicAtAddress(memory, frame, stackPointer - 1, opcode, address); + executeAtomicAtAddress(memory, memoryLib, frame, stackPointer - 1, opcode, address); return 0; } case Bytecode.ATOMIC_I32_STORE: @@ -2196,7 +2195,7 @@ private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, Wasm baseAddress = popLong(frame, stackPointer - 2); } final long address = effectiveMemoryAddress64(memOffset, baseAddress); - executeAtomicAtAddress(memory, frame, stackPointer - 1, opcode, address); + executeAtomicAtAddress(memory, memoryLib, frame, stackPointer - 1, opcode, address); return 2; } default: @@ -2204,396 +2203,396 @@ private int executeAtomic(VirtualFrame frame, int stackPointer, int opcode, Wasm } } - private void executeAtomicAtAddress(WasmMemory memory, VirtualFrame frame, int stackPointer, int opcode, long address) { + private void executeAtomicAtAddress(WasmMemory memory, WasmMemoryLibrary memoryLib, VirtualFrame frame, int stackPointer, int opcode, long address) { switch (opcode) { case Bytecode.ATOMIC_NOTIFY: { final int count = popInt(frame, stackPointer); - final int waitersNotified = memory.atomic_notify(this, address, count); + final int waitersNotified = memoryLib.atomic_notify(memory, this, address, count); pushInt(frame, stackPointer - 1, waitersNotified); break; } case Bytecode.ATOMIC_WAIT32: { final long timeout = popLong(frame, stackPointer); final int expected = popInt(frame, stackPointer - 1); - final int status = memory.atomic_wait32(this, address, expected, timeout); + final int status = memoryLib.atomic_wait32(memory, this, address, expected, timeout); pushInt(frame, stackPointer - 2, status); break; } case Bytecode.ATOMIC_WAIT64: { final long timeout = popLong(frame, stackPointer); final long expected = popLong(frame, stackPointer - 1); - final int status = memory.atomic_wait64(this, address, expected, timeout); + final int status = memoryLib.atomic_wait64(memory, this, address, expected, timeout); pushInt(frame, stackPointer - 2, status); break; } case Bytecode.ATOMIC_I32_LOAD: { - final int value = memory.atomic_load_i32(this, address); + final int value = memoryLib.atomic_load_i32(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I64_LOAD: { - final long value = memory.atomic_load_i64(this, address); + final long value = memoryLib.atomic_load_i64(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I32_LOAD8_U: { - final int value = memory.atomic_load_i32_8u(this, address); + final int value = memoryLib.atomic_load_i32_8u(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I32_LOAD16_U: { - final int value = memory.atomic_load_i32_16u(this, address); + final int value = memoryLib.atomic_load_i32_16u(memory, this, address); pushInt(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I64_LOAD8_U: { - final long value = memory.atomic_load_i64_8u(this, address); + final long value = memoryLib.atomic_load_i64_8u(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I64_LOAD16_U: { - final long value = memory.atomic_load_i64_16u(this, address); + final long value = memoryLib.atomic_load_i64_16u(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I64_LOAD32_U: { - final long value = memory.atomic_load_i64_32u(this, address); + final long value = memoryLib.atomic_load_i64_32u(memory, this, address); pushLong(frame, stackPointer, value); break; } case Bytecode.ATOMIC_I32_STORE: { final int value = popInt(frame, stackPointer); - memory.atomic_store_i32(this, address, value); + memoryLib.atomic_store_i32(memory, this, address, value); break; } case Bytecode.ATOMIC_I64_STORE: { final long value = popLong(frame, stackPointer); - memory.atomic_store_i64(this, address, value); + memoryLib.atomic_store_i64(memory, this, address, value); break; } case Bytecode.ATOMIC_I32_STORE8: { final int value = popInt(frame, stackPointer); - memory.atomic_store_i32_8(this, address, (byte) value); + memoryLib.atomic_store_i32_8(memory, this, address, (byte) value); break; } case Bytecode.ATOMIC_I32_STORE16: { final int value = popInt(frame, stackPointer); - memory.atomic_store_i32_16(this, address, (short) value); + memoryLib.atomic_store_i32_16(memory, this, address, (short) value); break; } case Bytecode.ATOMIC_I64_STORE8: { final long value = popLong(frame, stackPointer); - memory.atomic_store_i64_8(this, address, (byte) value); + memoryLib.atomic_store_i64_8(memory, this, address, (byte) value); break; } case Bytecode.ATOMIC_I64_STORE16: { final long value = popLong(frame, stackPointer); - memory.atomic_store_i64_16(this, address, (short) value); + memoryLib.atomic_store_i64_16(memory, this, address, (short) value); break; } case Bytecode.ATOMIC_I64_STORE32: { final long value = popLong(frame, stackPointer); - memory.atomic_store_i64_32(this, address, (int) value); + memoryLib.atomic_store_i64_32(memory, this, address, (int) value); break; } case Bytecode.ATOMIC_I32_RMW_ADD: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_add_i32(this, address, value); + final int result = memoryLib.atomic_rmw_add_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_ADD: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_add_i64(this, address, value); + final long result = memoryLib.atomic_rmw_add_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_ADD: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_add_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_add_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_ADD: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_add_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_add_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_ADD: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_add_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_add_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_ADD: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_add_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_add_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_ADD: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_add_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_add_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_SUB: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_sub_i32(this, address, value); + final int result = memoryLib.atomic_rmw_sub_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_SUB: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_sub_i64(this, address, value); + final long result = memoryLib.atomic_rmw_sub_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_SUB: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_sub_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_sub_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_SUB: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_sub_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_sub_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_SUB: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_sub_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_sub_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_SUB: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_sub_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_sub_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_SUB: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_sub_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_sub_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_AND: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_and_i32(this, address, value); + final int result = memoryLib.atomic_rmw_and_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_AND: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_and_i64(this, address, value); + final long result = memoryLib.atomic_rmw_and_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_AND: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_and_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_and_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_AND: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_and_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_and_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_AND: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_and_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_and_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_AND: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_and_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_and_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_AND: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_and_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_and_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_OR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_or_i32(this, address, value); + final int result = memoryLib.atomic_rmw_or_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_OR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_or_i64(this, address, value); + final long result = memoryLib.atomic_rmw_or_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_OR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_or_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_or_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_OR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_or_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_or_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_OR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_or_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_or_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_OR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_or_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_or_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_OR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_or_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_or_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_XOR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xor_i32(this, address, value); + final int result = memoryLib.atomic_rmw_xor_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_XOR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xor_i64(this, address, value); + final long result = memoryLib.atomic_rmw_xor_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_XOR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xor_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_xor_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_XOR: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xor_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_xor_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_XOR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xor_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_xor_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_XOR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xor_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_xor_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_XOR: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xor_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_xor_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_XCHG: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xchg_i32(this, address, value); + final int result = memoryLib.atomic_rmw_xchg_i32(memory, this, address, value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW_XCHG: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xchg_i64(this, address, value); + final long result = memoryLib.atomic_rmw_xchg_i64(memory, this, address, value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_XCHG: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xchg_i32_8u(this, address, (byte) value); + final int result = memoryLib.atomic_rmw_xchg_i32_8u(memory, this, address, (byte) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_XCHG: { final int value = popInt(frame, stackPointer); - final int result = memory.atomic_rmw_xchg_i32_16u(this, address, (short) value); + final int result = memoryLib.atomic_rmw_xchg_i32_16u(memory, this, address, (short) value); pushInt(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_XCHG: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xchg_i64_8u(this, address, (byte) value); + final long result = memoryLib.atomic_rmw_xchg_i64_8u(memory, this, address, (byte) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_XCHG: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xchg_i64_16u(this, address, (short) value); + final long result = memoryLib.atomic_rmw_xchg_i64_16u(memory, this, address, (short) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_XCHG: { final long value = popLong(frame, stackPointer); - final long result = memory.atomic_rmw_xchg_i64_32u(this, address, (int) value); + final long result = memoryLib.atomic_rmw_xchg_i64_32u(memory, this, address, (int) value); pushLong(frame, stackPointer - 1, result); break; } case Bytecode.ATOMIC_I32_RMW_CMPXCHG: { final int replacement = popInt(frame, stackPointer); final int expected = popInt(frame, stackPointer - 1); - final int result = memory.atomic_rmw_cmpxchg_i32(this, address, expected, replacement); + final int result = memoryLib.atomic_rmw_cmpxchg_i32(memory, this, address, expected, replacement); pushInt(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I64_RMW_CMPXCHG: { final long replacement = popLong(frame, stackPointer); final long expected = popLong(frame, stackPointer - 1); - final long result = memory.atomic_rmw_cmpxchg_i64(this, address, expected, replacement); + final long result = memoryLib.atomic_rmw_cmpxchg_i64(memory, this, address, expected, replacement); pushLong(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I32_RMW8_U_CMPXCHG: { final int replacement = popInt(frame, stackPointer); final int expected = popInt(frame, stackPointer - 1); - final int result = memory.atomic_rmw_cmpxchg_i32_8u(this, address, (byte) expected, (byte) replacement); + final int result = memoryLib.atomic_rmw_cmpxchg_i32_8u(memory, this, address, (byte) expected, (byte) replacement); pushInt(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I32_RMW16_U_CMPXCHG: { final int replacement = popInt(frame, stackPointer); final int expected = popInt(frame, stackPointer - 1); - final int result = memory.atomic_rmw_cmpxchg_i32_16u(this, address, (short) expected, (short) replacement); + final int result = memoryLib.atomic_rmw_cmpxchg_i32_16u(memory, this, address, (short) expected, (short) replacement); pushInt(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I64_RMW8_U_CMPXCHG: { final long replacement = popLong(frame, stackPointer); final long expected = popLong(frame, stackPointer - 1); - final long result = memory.atomic_rmw_cmpxchg_i64_8u(this, address, (byte) expected, (byte) replacement); + final long result = memoryLib.atomic_rmw_cmpxchg_i64_8u(memory, this, address, (byte) expected, (byte) replacement); pushLong(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I64_RMW16_U_CMPXCHG: { final long replacement = popLong(frame, stackPointer); final long expected = popLong(frame, stackPointer - 1); - final long result = memory.atomic_rmw_cmpxchg_i64_16u(this, address, (short) expected, (short) replacement); + final long result = memoryLib.atomic_rmw_cmpxchg_i64_16u(memory, this, address, (short) expected, (short) replacement); pushLong(frame, stackPointer - 2, result); break; } case Bytecode.ATOMIC_I64_RMW32_U_CMPXCHG: { final long replacement = popLong(frame, stackPointer); final long expected = popLong(frame, stackPointer - 1); - final long result = memory.atomic_rmw_cmpxchg_i64_32u(this, address, (int) expected, (int) replacement); + final long result = memoryLib.atomic_rmw_cmpxchg_i64_32u(memory, this, address, (int) expected, (int) replacement); pushLong(frame, stackPointer - 2, result); break; } @@ -2644,7 +2643,7 @@ private int executeVector(WasmInstance instance, VirtualFrame frame, int startin } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - loadVector(memory, frame, stackPointer++, vectorOpcode, address); + loadVector(memory, memoryLib(memoryIndex), frame, stackPointer++, vectorOpcode, address); break; } case Bytecode.VECTOR_V128_STORE: { @@ -2670,7 +2669,7 @@ private int executeVector(WasmInstance instance, VirtualFrame frame, int startin } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - storeVector(memory, address, value); + storeVector(memory, memoryLib(memoryIndex), address, value); break; } case Bytecode.VECTOR_V128_LOAD8_LANE: @@ -2701,7 +2700,7 @@ private int executeVector(WasmInstance instance, VirtualFrame frame, int startin } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - loadVectorLane(memory, frame, stackPointer++, vectorOpcode, address, laneIndex, vec); + loadVectorLane(memory, memoryLib(memoryIndex), frame, stackPointer++, vectorOpcode, address, laneIndex, vec); break; } case Bytecode.VECTOR_V128_STORE8_LANE: @@ -2732,7 +2731,7 @@ private int executeVector(WasmInstance instance, VirtualFrame frame, int startin } final long address = effectiveMemoryAddress64(memOffset, baseAddress); final WasmMemory memory = memory(instance, memoryIndex); - storeVectorLane(memory, vectorOpcode, address, laneIndex, vec); + storeVectorLane(memory, memoryLib(memoryIndex), vectorOpcode, address, laneIndex, vec); break; } case Bytecode.VECTOR_V128_CONST: { @@ -3133,16 +3132,16 @@ private int executeVector(WasmInstance instance, VirtualFrame frame, int startin return offset; } - private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, int vectorOpcode, long address) { + private void loadVector(WasmMemory memory, WasmMemoryLibrary memoryLib, VirtualFrame frame, int stackPointer, int vectorOpcode, long address) { switch (vectorOpcode) { case Bytecode.VECTOR_V128_LOAD: { - final Vector128 value = memory.load_i128(this, address); + final Vector128 value = memoryLib.load_i128(memory, this, address); pushVector128(frame, stackPointer, value); break; } case Bytecode.VECTOR_V128_LOAD8X8_S: case Bytecode.VECTOR_V128_LOAD8X8_U: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] bytes = new byte[8]; CompilerDirectives.ensureVirtualized(bytes); ByteArraySupport.littleEndian().putLong(bytes, 0, value); @@ -3162,7 +3161,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, } case Bytecode.VECTOR_V128_LOAD16X4_S: case Bytecode.VECTOR_V128_LOAD16X4_U: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] bytes = new byte[8]; CompilerDirectives.ensureVirtualized(bytes); ByteArraySupport.littleEndian().putLong(bytes, 0, value); @@ -3182,7 +3181,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, } case Bytecode.VECTOR_V128_LOAD32X2_S: case Bytecode.VECTOR_V128_LOAD32X2_U: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] bytes = new byte[8]; CompilerDirectives.ensureVirtualized(bytes); ByteArraySupport.littleEndian().putLong(bytes, 0, value); @@ -3201,7 +3200,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD8_SPLAT: { - final byte value = (byte) memory.load_i32_8s(this, address); + final byte value = (byte) memoryLib.load_i32_8s(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; Arrays.fill(resultBytes, value); final Vector128 vec = new Vector128(resultBytes); @@ -3209,7 +3208,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD16_SPLAT: { - final short value = (short) memory.load_i32_16s(this, address); + final short value = (short) memoryLib.load_i32_16s(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; for (int i = 0; i < Vector128.SHORT_LENGTH; i++) { ByteArraySupport.littleEndian().putShort(resultBytes, i * Short.BYTES, value); @@ -3219,7 +3218,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD32_SPLAT: { - final int value = memory.load_i32(this, address); + final int value = memoryLib.load_i32(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; for (int i = 0; i < Vector128.INT_LENGTH; i++) { ByteArraySupport.littleEndian().putInt(resultBytes, i * Integer.BYTES, value); @@ -3229,7 +3228,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD64_SPLAT: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; for (int i = 0; i < Vector128.LONG_LENGTH; i++) { ByteArraySupport.littleEndian().putLong(resultBytes, i * Long.BYTES, value); @@ -3239,7 +3238,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD32_ZERO: { - final int value = memory.load_i32(this, address); + final int value = memoryLib.load_i32(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; ByteArraySupport.littleEndian().putInt(resultBytes, 0, value); final Vector128 vec = new Vector128(resultBytes); @@ -3247,7 +3246,7 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, break; } case Bytecode.VECTOR_V128_LOAD64_ZERO: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] resultBytes = new byte[Vector128.BYTES]; ByteArraySupport.littleEndian().putLong(resultBytes, 0, value); final Vector128 vec = new Vector128(resultBytes); @@ -3259,35 +3258,35 @@ private void loadVector(WasmMemory memory, VirtualFrame frame, int stackPointer, } } - private void storeVector(WasmMemory memory, long address, Vector128 value) { - memory.store_i128(this, address, value); + private void storeVector(WasmMemory memory, WasmMemoryLibrary memoryLib, long address, Vector128 value) { + memoryLib.store_i128(memory, this, address, value); } - private void loadVectorLane(WasmMemory memory, VirtualFrame frame, int stackPointer, int vectorOpcode, long address, int laneIndex, Vector128 vec) { + private void loadVectorLane(WasmMemory memory, WasmMemoryLibrary memoryLib, VirtualFrame frame, int stackPointer, int vectorOpcode, long address, int laneIndex, Vector128 vec) { switch (vectorOpcode) { case Bytecode.VECTOR_V128_LOAD8_LANE: { - final byte value = (byte) memory.load_i32_8s(this, address); + final byte value = (byte) memoryLib.load_i32_8s(memory, this, address); byte[] resultBytes = Arrays.copyOf(vec.getBytes(), Vector128.BYTES); resultBytes[laneIndex] = value; pushVector128(frame, stackPointer, new Vector128(resultBytes)); break; } case Bytecode.VECTOR_V128_LOAD16_LANE: { - final short value = (short) memory.load_i32_16s(this, address); + final short value = (short) memoryLib.load_i32_16s(memory, this, address); byte[] resultBytes = Arrays.copyOf(vec.getBytes(), Vector128.BYTES); ByteArraySupport.littleEndian().putShort(resultBytes, laneIndex * Short.BYTES, value); pushVector128(frame, stackPointer, new Vector128(resultBytes)); break; } case Bytecode.VECTOR_V128_LOAD32_LANE: { - final int value = memory.load_i32(this, address); + final int value = memoryLib.load_i32(memory, this, address); byte[] resultBytes = Arrays.copyOf(vec.getBytes(), Vector128.BYTES); ByteArraySupport.littleEndian().putInt(resultBytes, laneIndex * Integer.BYTES, value); pushVector128(frame, stackPointer, new Vector128(resultBytes)); break; } case Bytecode.VECTOR_V128_LOAD64_LANE: { - final long value = memory.load_i64(this, address); + final long value = memoryLib.load_i64(memory, this, address); byte[] resultBytes = Arrays.copyOf(vec.getBytes(), Vector128.BYTES); ByteArraySupport.littleEndian().putLong(resultBytes, laneIndex * Long.BYTES, value); pushVector128(frame, stackPointer, new Vector128(resultBytes)); @@ -3298,26 +3297,26 @@ private void loadVectorLane(WasmMemory memory, VirtualFrame frame, int stackPoin } } - private void storeVectorLane(WasmMemory memory, int vectorOpcode, long address, int laneIndex, Vector128 vec) { + private void storeVectorLane(WasmMemory memory, WasmMemoryLibrary memoryLib, int vectorOpcode, long address, int laneIndex, Vector128 vec) { switch (vectorOpcode) { case Bytecode.VECTOR_V128_STORE8_LANE: { byte value = vec.getBytes()[laneIndex]; - memory.store_i32_8(this, address, value); + memoryLib.store_i32_8(memory, this, address, value); break; } case Bytecode.VECTOR_V128_STORE16_LANE: { short value = ByteArraySupport.littleEndian().getShort(vec.getBytes(), laneIndex * Short.BYTES); - memory.store_i32_16(this, address, value); + memoryLib.store_i32_16(memory, this, address, value); break; } case Bytecode.VECTOR_V128_STORE32_LANE: { int value = ByteArraySupport.littleEndian().getInt(vec.getBytes(), laneIndex * Integer.BYTES); - memory.store_i32(this, address, value); + memoryLib.store_i32(memory, this, address, value); break; } case Bytecode.VECTOR_V128_STORE64_LANE: { long value = ByteArraySupport.littleEndian().getLong(vec.getBytes(), laneIndex * Long.BYTES); - memory.store_i64(this, address, value); + memoryLib.store_i64(memory, this, address, value); break; } default: @@ -4484,14 +4483,14 @@ private void memory_init(WasmInstance instance, int length, int source, long des final WasmMemory memory = memory(instance, memoryIndex); final int dataOffset = instance.dataInstanceOffset(dataIndex); final int dataLength = instance.dataInstanceLength(dataIndex); - if (checkOutOfBounds(source, length, dataLength) || checkOutOfBounds(destination, length, memory.byteSize())) { + if (checkOutOfBounds(source, length, dataLength) || checkOutOfBounds(destination, length, memoryLib(memoryIndex).byteSize(memory))) { enterErrorBranch(); throw WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); } if (length == 0) { return; } - memory.initialize(codeEntry.bytecode(), dataOffset + source, destination, length); + memoryLib(memoryIndex).initialize(memory, codeEntry.bytecode(), dataOffset + source, destination, length); } @TruffleBoundary @@ -4499,14 +4498,14 @@ private void memory_init_unsafe(WasmInstance instance, int length, int source, l final WasmMemory memory = memory(instance, memoryIndex); final long dataAddress = instance.dataInstanceAddress(dataIndex); final int dataLength = instance.dataInstanceLength(dataIndex); - if (checkOutOfBounds(source, length, dataLength) || checkOutOfBounds(destination, length, memory.byteSize())) { + if (checkOutOfBounds(source, length, dataLength) || checkOutOfBounds(destination, length, memoryLib(memoryIndex).byteSize(memory))) { enterErrorBranch(); throw WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); } if (length == 0) { return; } - memory.initializeUnsafe(dataAddress, source, destination, length); + memoryLib(memoryIndex).initializeUnsafe(memory, dataAddress, source, destination, length); } @TruffleBoundary @@ -4522,28 +4521,28 @@ private static void data_drop_unsafe(WasmInstance instance, int dataIndex) { @TruffleBoundary private void memory_fill(WasmInstance instance, long length, int value, long offset, int memoryIndex) { final WasmMemory memory = memory(instance, memoryIndex); - if (checkOutOfBounds(offset, length, memory.byteSize())) { + if (checkOutOfBounds(offset, length, memoryLib(memoryIndex).byteSize(memory))) { enterErrorBranch(); throw WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); } if (length == 0L) { return; } - memory.fill(offset, length, (byte) value); + memoryLib(memoryIndex).fill(memory, offset, length, (byte) value); } @TruffleBoundary private void memory_copy(WasmInstance instance, long length, long source, long destination, int destMemoryIndex, int srcMemoryIndex) { final WasmMemory destMemory = memory(instance, destMemoryIndex); final WasmMemory srcMemory = memory(instance, srcMemoryIndex); - if (checkOutOfBounds(source, length, srcMemory.byteSize()) || checkOutOfBounds(destination, length, destMemory.byteSize())) { + if (checkOutOfBounds(source, length, memoryLib(srcMemoryIndex).byteSize(srcMemory)) || checkOutOfBounds(destination, length, memoryLib(destMemoryIndex).byteSize(destMemory))) { enterErrorBranch(); throw WasmException.create(Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); } if (length == 0L) { return; } - destMemory.copyFrom(srcMemory, source, destination, length); + memoryLib(destMemoryIndex).copyFrom(destMemory, srcMemory, source, destination, length); } // Checkstyle: resume method name check @@ -4556,18 +4555,6 @@ private static boolean checkOutOfBounds(int offset, int length, int size) { return offset < 0 || length < 0 || offset + length < 0 || offset + length > size; } - @TruffleBoundary - public void resolveCallNode(WasmInstance instance, int callNodeIndex, int bytecodeOffset) { - Node unresolvedCallNode = callNodes[callNodeIndex]; - if (unresolvedCallNode instanceof WasmCallStubNode) { - final WasmFunction function = ((WasmCallStubNode) unresolvedCallNode).function(); - final CallTarget target = instance.target(function.index()); - callNodes[callNodeIndex] = insert(WasmDirectCallNode.create(target, bytecodeOffset)); - } else { - assert unresolvedCallNode instanceof WasmIndirectCallNode : unresolvedCallNode; - } - } - @ExplodeLoop private Object[] createArgumentsForCall(VirtualFrame frame, int functionTypeIndex, int numArgs, int stackPointerOffset) { CompilerAsserts.partialEvaluationConstant(numArgs); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionRootNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionRootNode.java new file mode 100644 index 000000000000..535f1c1d3cca --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmFunctionRootNode.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.nodes; + +import static org.graalvm.wasm.nodes.WasmFrame.popDouble; +import static org.graalvm.wasm.nodes.WasmFrame.popFloat; +import static org.graalvm.wasm.nodes.WasmFrame.popInt; +import static org.graalvm.wasm.nodes.WasmFrame.popLong; +import static org.graalvm.wasm.nodes.WasmFrame.popReference; +import static org.graalvm.wasm.nodes.WasmFrame.popVector128; +import static org.graalvm.wasm.nodes.WasmFrame.pushDouble; +import static org.graalvm.wasm.nodes.WasmFrame.pushFloat; +import static org.graalvm.wasm.nodes.WasmFrame.pushInt; +import static org.graalvm.wasm.nodes.WasmFrame.pushLong; +import static org.graalvm.wasm.nodes.WasmFrame.pushReference; +import static org.graalvm.wasm.nodes.WasmFrame.pushVector128; + +import com.oracle.truffle.api.CompilerDirectives; +import org.graalvm.collections.EconomicMap; +import org.graalvm.wasm.WasmArguments; +import org.graalvm.wasm.WasmCodeEntry; +import org.graalvm.wasm.WasmConstant; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.WasmModule; +import org.graalvm.wasm.WasmType; +import org.graalvm.wasm.api.Vector128; +import org.graalvm.wasm.debugging.data.DebugFunction; +import org.graalvm.wasm.exception.Failure; +import org.graalvm.wasm.exception.WasmException; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.TruffleLanguage; +import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.NodeInfo; +import com.oracle.truffle.api.source.SourceSection; + +@NodeInfo(language = WasmLanguage.ID, description = "The root node of all WebAssembly functions") +public class WasmFunctionRootNode extends WasmRootNode { + + @Child private WasmFixedMemoryImplFunctionNode functionNode; + private final WasmCodeEntry codeEntry; + + private SourceSection sourceSection; + + public WasmFunctionRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, WasmModule module, WasmFixedMemoryImplFunctionNode functionNode, WasmCodeEntry codeEntry) { + super(language, frameDescriptor, module); + this.functionNode = functionNode; + this.codeEntry = codeEntry; + } + + int localCount() { + return codeEntry.localCount(); + } + + int resultCount() { + return codeEntry.resultCount(); + } + + void enterErrorBranch() { + codeEntry.errorBranch(); + } + + byte resultType(int index) { + return codeEntry.resultType(index); + } + + int paramCount() { + return module().symbolTable().function(codeEntry.functionIndex()).paramCount(); + } + + byte localType(int index) { + return codeEntry.localType(index); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance) { + // WebAssembly structure dictates that a function's arguments are provided to the function + // as local variables, followed by any additional local variables that the function + // declares. A VirtualFrame contains a special array for the arguments, so we need to move + // the arguments to the array that holds the locals. + // + // The operand stack is also represented in the same long array. + // + // This combined array is kept inside a frame slot. + // The reason for this is that the operand stack cannot be passed + // as an argument to the loop-node's execute method, + // and must be restored at the beginning of the loop body. + final int localCount = localCount(); + moveArgumentsToLocals(frame); + + // WebAssembly rules dictate that a function's locals must be initialized to zero before + // function invocation. For more information, check the specification: + // https://webassembly.github.io/spec/core/exec/instructions.html#function-calls + initializeLocals(frame); + + final int resultCount = resultCount(); + CompilerAsserts.partialEvaluationConstant(resultCount); + if (resultCount > 1) { + WasmLanguage.get(this).multiValueStack().resize(resultCount); + } + + try { + functionNode.execute(frame, context, instance); + } catch (StackOverflowError e) { + enterErrorBranch(); + throw WasmException.create(Failure.CALL_STACK_EXHAUSTED); + } + if (resultCount == 0) { + return WasmConstant.VOID; + } else if (resultCount == 1) { + final byte resultType = resultType(0); + CompilerAsserts.partialEvaluationConstant(resultType); + switch (resultType) { + case WasmType.VOID_TYPE: + return WasmConstant.VOID; + case WasmType.I32_TYPE: + return popInt(frame, localCount); + case WasmType.I64_TYPE: + return popLong(frame, localCount); + case WasmType.F32_TYPE: + return popFloat(frame, localCount); + case WasmType.F64_TYPE: + return popDouble(frame, localCount); + case WasmType.V128_TYPE: + return popVector128(frame, localCount); + case WasmType.FUNCREF_TYPE: + case WasmType.EXTERNREF_TYPE: + return popReference(frame, localCount); + default: + throw WasmException.format(Failure.UNSPECIFIED_INTERNAL, this, "Unknown result type: %d", resultType); + } + } else { + moveResultValuesToMultiValueStack(frame, resultCount, localCount); + return WasmConstant.MULTI_VALUE; + } + } + + @ExplodeLoop + private void moveResultValuesToMultiValueStack(VirtualFrame frame, int resultCount, int localCount) { + CompilerAsserts.partialEvaluationConstant(resultCount); + final var multiValueStack = WasmLanguage.get(this).multiValueStack(); + final long[] primitiveMultiValueStack = multiValueStack.primitiveStack(); + final Object[] objectMultiValueStack = multiValueStack.objectStack(); + for (int i = 0; i < resultCount; i++) { + final int resultType = resultType(i); + CompilerAsserts.partialEvaluationConstant(resultType); + switch (resultType) { + case WasmType.I32_TYPE: + primitiveMultiValueStack[i] = popInt(frame, localCount + i); + break; + case WasmType.I64_TYPE: + primitiveMultiValueStack[i] = popLong(frame, localCount + i); + break; + case WasmType.F32_TYPE: + primitiveMultiValueStack[i] = Float.floatToRawIntBits(popFloat(frame, localCount + i)); + break; + case WasmType.F64_TYPE: + primitiveMultiValueStack[i] = Double.doubleToRawLongBits(popDouble(frame, localCount + i)); + break; + case WasmType.V128_TYPE: + objectMultiValueStack[i] = popVector128(frame, localCount + i); + break; + case WasmType.FUNCREF_TYPE: + case WasmType.EXTERNREF_TYPE: + objectMultiValueStack[i] = popReference(frame, localCount + i); + break; + default: + throw WasmException.format(Failure.UNSPECIFIED_INTERNAL, this, "Unknown result type: %d", resultType); + } + } + } + + @ExplodeLoop + private void moveArgumentsToLocals(VirtualFrame frame) { + Object[] args = frame.getArguments(); + int paramCount = paramCount(); + assert WasmArguments.getArgumentCount(args) == paramCount : "Expected number of params " + paramCount + ", actual " + WasmArguments.getArgumentCount(args); + for (int i = 0; i != paramCount; ++i) { + final Object arg = WasmArguments.getArgument(args, i); + byte type = localType(i); + switch (type) { + case WasmType.I32_TYPE: + pushInt(frame, i, (int) arg); + break; + case WasmType.I64_TYPE: + pushLong(frame, i, (long) arg); + break; + case WasmType.F32_TYPE: + pushFloat(frame, i, (float) arg); + break; + case WasmType.F64_TYPE: + pushDouble(frame, i, (double) arg); + break; + case WasmType.V128_TYPE: + pushVector128(frame, i, (Vector128) arg); + break; + case WasmType.FUNCREF_TYPE: + case WasmType.EXTERNREF_TYPE: + pushReference(frame, i, arg); + break; + } + } + } + + @ExplodeLoop + private void initializeLocals(VirtualFrame frame) { + int paramCount = paramCount(); + for (int i = paramCount; i != localCount(); ++i) { + byte type = localType(i); + switch (type) { + case WasmType.I32_TYPE: + pushInt(frame, i, 0); + break; + case WasmType.I64_TYPE: + pushLong(frame, i, 0L); + break; + case WasmType.F32_TYPE: + pushFloat(frame, i, 0F); + break; + case WasmType.F64_TYPE: + pushDouble(frame, i, 0D); + break; + case WasmType.V128_TYPE: + pushVector128(frame, i, Vector128.ZERO); + break; + case WasmType.FUNCREF_TYPE: + case WasmType.EXTERNREF_TYPE: + pushReference(frame, i, WasmConstant.NULL); + break; + } + } + } + + @CompilerDirectives.TruffleBoundary + private DebugFunction debugFunction() { + if (module().hasDebugInfo()) { + int functionSourceLocation = module().functionSourceCodeStartOffset(codeEntry.functionIndex()); + final EconomicMap debugFunctions = module().debugFunctions(this); + if (debugFunctions.containsKey(functionSourceLocation)) { + return debugFunctions.get(functionSourceLocation); + } + } + return null; + } + + @Override + public String getName() { + final DebugFunction function = debugFunction(); + return function != null ? function.name() : codeEntry.function().name(); + } + + @Override + public final String getQualifiedName() { + return codeEntry.function().moduleName() + "." + getName(); + } + + @Override + @CompilerDirectives.TruffleBoundary + protected boolean isInstrumentable() { + final DebugFunction debugFunction = debugFunction(); + if (debugFunction == null) { + return false; + } + return debugFunction.sourceSection() != null; + } + + @Override + @CompilerDirectives.TruffleBoundary + public final SourceSection getSourceSection() { + if (sourceSection == null) { + final DebugFunction debugFunction = debugFunction(); + if (debugFunction != null) { + sourceSection = debugFunction.sourceSection(); + } else { + sourceSection = module().source().createUnavailableSection(); + } + } + return sourceSection; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmInstrumentableFunctionNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmInstrumentableFunctionNode.java index 722971b08db6..03506720b3e1 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmInstrumentableFunctionNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmInstrumentableFunctionNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -69,6 +69,7 @@ import com.oracle.truffle.api.library.ExportMessage; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.SourceSection; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** * Represents an instrumentable Wasm function node. See {@link WasmFunctionNode} for a description @@ -84,11 +85,14 @@ public class WasmInstrumentableFunctionNode extends Node implements Instrumentab @Child private WasmFunctionNode functionNode; @Child private WasmInstrumentationSupportNode instrumentation; - public WasmInstrumentableFunctionNode(WasmModule module, WasmCodeEntry codeEntry, WasmFunctionNode functionNode, int functionSourceLocation) { + @Child private WasmMemoryLibrary zeroMemoryLib; + + public WasmInstrumentableFunctionNode(WasmModule module, WasmCodeEntry codeEntry, int bytecodeStartOffset, int bytecodeEndOffset, Node[] callNodes, WasmMemoryLibrary[] memoryLibs) { this.module = module; this.codeEntry = codeEntry; - this.functionNode = functionNode; - this.functionSourceLocation = functionSourceLocation; + this.functionNode = new WasmFunctionNode(module, codeEntry, bytecodeStartOffset, bytecodeEndOffset, callNodes, memoryLibs); + this.functionSourceLocation = module.functionSourceCodeStartOffset(codeEntry.functionIndex()); + this.zeroMemoryLib = module.memoryCount() > 0 ? memoryLibs[0] : null; } protected WasmInstrumentableFunctionNode(WasmInstrumentableFunctionNode node) { @@ -97,6 +101,7 @@ protected WasmInstrumentableFunctionNode(WasmInstrumentableFunctionNode node) { this.functionNode = node.functionNode; this.functionSourceLocation = node.functionSourceLocation; this.instrumentation = node.instrumentation; + this.zeroMemoryLib = node.zeroMemoryLib; } private WasmInstance instance(VirtualFrame frame) { @@ -104,52 +109,17 @@ private WasmInstance instance(VirtualFrame frame) { } private WasmMemory memory0(MaterializedFrame frame) { - return module.memory(instance(frame), 0); - } - - final WasmModule module() { - return module; + return instance(frame).memory(0); } int localCount() { return codeEntry.localCount(); } - int resultCount() { - return codeEntry.resultCount(); - } - void execute(VirtualFrame frame, WasmContext context, WasmInstance instance) { functionNode.execute(frame, context, instance); } - void enterErrorBranch() { - codeEntry.errorBranch(); - } - - byte resultType(int index) { - return codeEntry.resultType(index); - } - - int paramCount() { - return module.symbolTable().function(codeEntry.functionIndex()).paramCount(); - } - - byte localType(int index) { - return codeEntry.localType(index); - } - - @TruffleBoundary - public String name() { - final DebugFunction function = debugFunction(); - return function != null ? function.name() : codeEntry.function().name(); - } - - @TruffleBoundary - String qualifiedName() { - return codeEntry.function().moduleName() + "." + name(); - } - @TruffleBoundary public boolean isInstrumentable() { return getSourceSection() != null; @@ -319,50 +289,50 @@ public double loadF64FromGlobals(MaterializedFrame frame, int index) { @Override public boolean isValidMemoryAddress(MaterializedFrame frame, long address, int length) { final WasmMemory memory = memory0(frame); - return address >= 0 && address + length < memory.byteSize(); + return address >= 0 && address + length < zeroMemoryLib.byteSize(memory); } @TruffleBoundary public byte loadI8FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return (byte) memory.load_i32_8s(this, address); + return (byte) zeroMemoryLib.load_i32_8s(memory, this, address); } @TruffleBoundary public short loadI16FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return (short) memory.load_i32_16s(this, address); + return (short) zeroMemoryLib.load_i32_16s(memory, this, address); } @TruffleBoundary public int loadI32FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return memory.load_i32(this, address); + return zeroMemoryLib.load_i32(memory, this, address); } @TruffleBoundary public long loadI64FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return memory.load_i64(this, address); + return zeroMemoryLib.load_i64(memory, this, address); } @TruffleBoundary public float loadF32FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return memory.load_f32(this, address); + return zeroMemoryLib.load_f32(memory, this, address); } @TruffleBoundary public double loadF64FromMemory(MaterializedFrame frame, long address) { final WasmMemory memory = memory0(frame); - return memory.load_f64(this, address); + return zeroMemoryLib.load_f64(memory, this, address); } private byte[] loadByteArrayFromMemory(MaterializedFrame frame, long address, int length) { final WasmMemory memory = memory0(frame); byte[] dataArray = new byte[length]; for (int i = 0; i < length; i++) { - dataArray[i] = (byte) memory.load_i32_8s(this, address + i); + dataArray[i] = (byte) zeroMemoryLib.load_i32_8s(memory, this, address + i); } return dataArray; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeRootNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeFunctionRootNode.java similarity index 85% rename from wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeRootNode.java rename to wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeFunctionRootNode.java index 0375db275e13..0d7aa645452b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeRootNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmMemoryOverheadModeFunctionRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,8 +44,10 @@ import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmCodeEntry; import org.graalvm.wasm.WasmContext; import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmModule; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; import org.graalvm.wasm.WasmOptions; @@ -56,10 +58,11 @@ * {@link WasmOptions#MemoryOverheadMode}, since memories, tables, etc. are not initialized and code * execution would lead to unexpected results. */ -public class WasmMemoryOverheadModeRootNode extends WasmRootNode { +public class WasmMemoryOverheadModeFunctionRootNode extends WasmFunctionRootNode { - public WasmMemoryOverheadModeRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, WasmInstrumentableFunctionNode functionNode) { - super(language, frameDescriptor, functionNode); + public WasmMemoryOverheadModeFunctionRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, WasmModule module, WasmFixedMemoryImplFunctionNode functionNode, + WasmCodeEntry codeEntry) { + super(language, frameDescriptor, module, functionNode, codeEntry); } @Override diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java index ea01ae30db04..3a793bbf7f45 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/nodes/WasmRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,67 +40,43 @@ */ package org.graalvm.wasm.nodes; -import static org.graalvm.wasm.nodes.WasmFrame.popDouble; -import static org.graalvm.wasm.nodes.WasmFrame.popFloat; -import static org.graalvm.wasm.nodes.WasmFrame.popInt; -import static org.graalvm.wasm.nodes.WasmFrame.popLong; -import static org.graalvm.wasm.nodes.WasmFrame.popReference; -import static org.graalvm.wasm.nodes.WasmFrame.popVector128; -import static org.graalvm.wasm.nodes.WasmFrame.pushDouble; -import static org.graalvm.wasm.nodes.WasmFrame.pushFloat; -import static org.graalvm.wasm.nodes.WasmFrame.pushInt; -import static org.graalvm.wasm.nodes.WasmFrame.pushLong; -import static org.graalvm.wasm.nodes.WasmFrame.pushReference; -import static org.graalvm.wasm.nodes.WasmFrame.pushVector128; - import org.graalvm.wasm.WasmArguments; -import org.graalvm.wasm.WasmConstant; import org.graalvm.wasm.WasmContext; import org.graalvm.wasm.WasmInstance; import org.graalvm.wasm.WasmLanguage; import org.graalvm.wasm.WasmModule; -import org.graalvm.wasm.WasmType; -import org.graalvm.wasm.api.Vector128; -import org.graalvm.wasm.exception.Failure; -import org.graalvm.wasm.exception.WasmException; -import org.graalvm.wasm.memory.WasmMemory; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleLanguage; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.BranchProfile; -import com.oracle.truffle.api.source.SourceSection; @NodeInfo(language = WasmLanguage.ID, description = "The root node of all WebAssembly functions") -public class WasmRootNode extends RootNode { - private SourceSection sourceSection; - @Child private WasmInstrumentableFunctionNode functionNode; +public abstract class WasmRootNode extends RootNode { + + private final WasmModule module; + private final BranchProfile nonLinkedProfile = BranchProfile.create(); /** Bound module instance (single-context mode only). */ @CompilationFinal private WasmInstance boundInstance; - public WasmRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, WasmInstrumentableFunctionNode functionNode) { + public WasmRootNode(TruffleLanguage language, FrameDescriptor frameDescriptor, WasmModule module) { super(language, frameDescriptor); - this.functionNode = functionNode; + this.module = module; } protected final WasmContext getContext() { return WasmContext.get(this); } - /** - * Overridden by {@link org.graalvm.wasm.predefined.WasmBuiltinRootNode}. - */ protected WasmModule module() { - return functionNode.module(); + return module; } @SuppressWarnings("static-method") @@ -147,14 +123,6 @@ public final void setBoundModuleInstance(WasmInstance boundInstance) { this.boundInstance = boundInstance; } - protected final WasmMemory memory(VirtualFrame frame) { - return memory(frame, 0); - } - - protected final WasmMemory memory(VirtualFrame frame, int index) { - return module().memory(instance(frame), index); - } - @Override public Object execute(VirtualFrame frame) { assert WasmArguments.isValid(frame.getArguments()); @@ -164,163 +132,7 @@ public Object execute(VirtualFrame frame) { return executeWithContext(frame, context, instance); } - public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance) { - // WebAssembly structure dictates that a function's arguments are provided to the function - // as local variables, followed by any additional local variables that the function - // declares. A VirtualFrame contains a special array for the arguments, so we need to move - // the arguments to the array that holds the locals. - // - // The operand stack is also represented in the same long array. - // - // This combined array is kept inside a frame slot. - // The reason for this is that the operand stack cannot be passed - // as an argument to the loop-node's execute method, - // and must be restored at the beginning of the loop body. - final int localCount = functionNode.localCount(); - moveArgumentsToLocals(frame); - - // WebAssembly rules dictate that a function's locals must be initialized to zero before - // function invocation. For more information, check the specification: - // https://webassembly.github.io/spec/core/exec/instructions.html#function-calls - initializeLocals(frame); - - final int resultCount = functionNode.resultCount(); - CompilerAsserts.partialEvaluationConstant(resultCount); - if (resultCount > 1) { - WasmLanguage.get(this).multiValueStack().resize(resultCount); - } - - try { - functionNode.execute(frame, context, instance); - } catch (StackOverflowError e) { - functionNode.enterErrorBranch(); - throw WasmException.create(Failure.CALL_STACK_EXHAUSTED); - } - if (resultCount == 0) { - return WasmConstant.VOID; - } else if (resultCount == 1) { - final byte resultType = functionNode.resultType(0); - CompilerAsserts.partialEvaluationConstant(resultType); - switch (resultType) { - case WasmType.VOID_TYPE: - return WasmConstant.VOID; - case WasmType.I32_TYPE: - return popInt(frame, localCount); - case WasmType.I64_TYPE: - return popLong(frame, localCount); - case WasmType.F32_TYPE: - return popFloat(frame, localCount); - case WasmType.F64_TYPE: - return popDouble(frame, localCount); - case WasmType.V128_TYPE: - return popVector128(frame, localCount); - case WasmType.FUNCREF_TYPE: - case WasmType.EXTERNREF_TYPE: - return popReference(frame, localCount); - default: - throw WasmException.format(Failure.UNSPECIFIED_INTERNAL, this, "Unknown result type: %d", resultType); - } - } else { - moveResultValuesToMultiValueStack(frame, resultCount, localCount); - return WasmConstant.MULTI_VALUE; - } - } - - @ExplodeLoop - private void moveResultValuesToMultiValueStack(VirtualFrame frame, int resultCount, int localCount) { - CompilerAsserts.partialEvaluationConstant(resultCount); - final var multiValueStack = WasmLanguage.get(this).multiValueStack(); - final long[] primitiveMultiValueStack = multiValueStack.primitiveStack(); - final Object[] objectMultiValueStack = multiValueStack.objectStack(); - for (int i = 0; i < resultCount; i++) { - final int resultType = functionNode.resultType(i); - CompilerAsserts.partialEvaluationConstant(resultType); - switch (resultType) { - case WasmType.I32_TYPE: - primitiveMultiValueStack[i] = popInt(frame, localCount + i); - break; - case WasmType.I64_TYPE: - primitiveMultiValueStack[i] = popLong(frame, localCount + i); - break; - case WasmType.F32_TYPE: - primitiveMultiValueStack[i] = Float.floatToRawIntBits(popFloat(frame, localCount + i)); - break; - case WasmType.F64_TYPE: - primitiveMultiValueStack[i] = Double.doubleToRawLongBits(popDouble(frame, localCount + i)); - break; - case WasmType.V128_TYPE: - objectMultiValueStack[i] = popVector128(frame, localCount + i); - break; - case WasmType.FUNCREF_TYPE: - case WasmType.EXTERNREF_TYPE: - objectMultiValueStack[i] = popReference(frame, localCount + i); - break; - default: - throw WasmException.format(Failure.UNSPECIFIED_INTERNAL, this, "Unknown result type: %d", resultType); - } - } - } - - @ExplodeLoop - private void moveArgumentsToLocals(VirtualFrame frame) { - Object[] args = frame.getArguments(); - int paramCount = functionNode.paramCount(); - assert WasmArguments.getArgumentCount(args) == paramCount : "Expected number of params " + paramCount + ", actual " + WasmArguments.getArgumentCount(args); - for (int i = 0; i != paramCount; ++i) { - final Object arg = WasmArguments.getArgument(args, i); - byte type = functionNode.localType(i); - switch (type) { - case WasmType.I32_TYPE: - pushInt(frame, i, (int) arg); - break; - case WasmType.I64_TYPE: - pushLong(frame, i, (long) arg); - break; - case WasmType.F32_TYPE: - pushFloat(frame, i, (float) arg); - break; - case WasmType.F64_TYPE: - pushDouble(frame, i, (double) arg); - break; - case WasmType.V128_TYPE: - pushVector128(frame, i, (Vector128) arg); - break; - case WasmType.FUNCREF_TYPE: - case WasmType.EXTERNREF_TYPE: - pushReference(frame, i, arg); - break; - } - } - } - - @ExplodeLoop - private void initializeLocals(VirtualFrame frame) { - int paramCount = functionNode.paramCount(); - for (int i = paramCount; i != functionNode.localCount(); ++i) { - byte type = functionNode.localType(i); - switch (type) { - case WasmType.I32_TYPE: - pushInt(frame, i, 0); - break; - case WasmType.I64_TYPE: - pushLong(frame, i, 0L); - break; - case WasmType.F32_TYPE: - pushFloat(frame, i, 0F); - break; - case WasmType.F64_TYPE: - pushDouble(frame, i, 0D); - break; - case WasmType.V128_TYPE: - pushVector128(frame, i, Vector128.ZERO); - break; - case WasmType.FUNCREF_TYPE: - case WasmType.EXTERNREF_TYPE: - pushReference(frame, i, WasmConstant.NULL); - break; - } - } - } + public abstract Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance); @Override public final String toString() { @@ -328,39 +140,7 @@ public final String toString() { } @Override - public String getName() { - if (functionNode == null) { - return "function"; - } - return functionNode.name(); - } - - @Override - public final String getQualifiedName() { - if (functionNode == null) { - return getName(); - } - return functionNode.qualifiedName(); - } - - @Override - @TruffleBoundary protected boolean isInstrumentable() { - return functionNode != null && functionNode.isInstrumentable(); - } - - @Override - @TruffleBoundary - public final SourceSection getSourceSection() { - if (functionNode == null) { - return null; - } - if (sourceSection == null) { - sourceSection = functionNode.getSourceSection(); - if (sourceSection == null) { - sourceSection = module().source().createUnavailableSection(); - } - } - return sourceSection; + return false; } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java index 9d6df0ec3a24..1b19caa6e68a 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/parser/bytecode/BytecodeParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -65,6 +65,7 @@ import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.memory.NativeDataInstanceUtil; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.parser.ir.CallNode; import org.graalvm.wasm.parser.ir.CodeEntry; @@ -195,10 +196,11 @@ public static void resetMemoryState(WasmContext context, WasmModule module, Wasm // Reading of the data segment is called after linking, so initialize the memory // directly. final WasmMemory memory = instance.memory(memoryIndex); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); - Assert.assertUnsignedLongLessOrEqual(offsetAddress, memory.byteSize(), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); - Assert.assertUnsignedLongLessOrEqual(offsetAddress + dataLength, memory.byteSize(), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); - memory.initialize(module.bytecode(), effectiveOffset, offsetAddress, dataLength); + Assert.assertUnsignedLongLessOrEqual(offsetAddress, memoryLib.byteSize(memory), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); + Assert.assertUnsignedLongLessOrEqual(offsetAddress + dataLength, memoryLib.byteSize(memory), Failure.OUT_OF_BOUNDS_MEMORY_ACCESS); + memoryLib.initialize(memory, module.bytecode(), effectiveOffset, offsetAddress, dataLength); } else { if (unsafeMemory) { final int length = switch (bytecode[effectiveOffset] & BytecodeBitEncoding.DATA_SEG_RUNTIME_LENGTH_MASK) { diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java index c10d3a791729..5d488c08f45e 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/BuiltinModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -139,9 +139,10 @@ protected int defineTable(WasmContext context, WasmModule module, String tableNa protected void defineMemory(WasmContext context, WasmModule module, String memoryName, int initSize, int maxSize, boolean is64Bit, boolean isShared) { final boolean useUnsafeMemory = context.getContextOptions().useUnsafeMemory(); + final boolean directByteBufferMemoryAccess = context.getContextOptions().directByteBufferMemoryAccess(); int index = module.symbolTable().memoryCount(); // set multiMemory flag to true, since spectest module has multiple memories - module.symbolTable().allocateMemory(index, initSize, maxSize, is64Bit, isShared, true, useUnsafeMemory); + module.symbolTable().allocateMemory(index, initSize, maxSize, is64Bit, isShared, true, useUnsafeMemory, directByteBufferMemoryAccess); module.symbolTable().exportMemory(index, memoryName); } @@ -153,9 +154,8 @@ protected void importFunction(WasmContext context, WasmModule module, String imp protected void importMemory(WasmContext context, WasmModule module, String importModuleName, String memoryName, int initSize, long maxSize, boolean is64Bit, boolean isShared) { final boolean multiMemory = context.getContextOptions().supportMultiMemory(); - final boolean useUnsafeMemory = context.getContextOptions().useUnsafeMemory(); int index = module.symbolTable().memoryCount(); - module.symbolTable().importMemory(importModuleName, memoryName, index, initSize, maxSize, is64Bit, isShared, multiMemory, useUnsafeMemory); + module.symbolTable().importMemory(importModuleName, memoryName, index, initSize, maxSize, is64Bit, isShared, multiMemory); } protected static byte[] types(byte... args) { diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/WasmBuiltinRootNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/WasmBuiltinRootNode.java index babe86ba1b82..a557ef849dd3 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/WasmBuiltinRootNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/WasmBuiltinRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,28 +40,34 @@ */ package org.graalvm.wasm.predefined; +import com.oracle.truffle.api.frame.VirtualFrame; import org.graalvm.wasm.WasmLanguage; import org.graalvm.wasm.WasmModule; +import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.nodes.WasmRootNode; public abstract class WasmBuiltinRootNode extends WasmRootNode { - protected final WasmModule module; + + @Child protected WasmMemoryLibrary memoryLib; protected WasmBuiltinRootNode(WasmLanguage language, WasmModule module) { - super(language, null, null); - this.module = module; + super(language, null, module); + this.memoryLib = insert(WasmMemoryLibrary.getFactory().createDispatched(3)); } public abstract String builtinNodeName(); - @Override - protected final WasmModule module() { - return module; + protected final WasmMemory memory(VirtualFrame frame, int index) { + return instance(frame).memory(index); + } + + protected final WasmMemory memory(VirtualFrame frame) { + return memory(frame, 0); } @Override public String getName() { return "wasm-function:" + builtinNodeName(); } - } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenGetHeapSizeNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenGetHeapSizeNode.java index b63e4d1256c5..c1f4fd8a8b6d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenGetHeapSizeNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenGetHeapSizeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -57,7 +57,7 @@ public EmscriptenGetHeapSizeNode(WasmLanguage language, WasmModule module) { @Override public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmInstance instance) { WasmMemory memory = memory(frame); - final long byteSize = memory.byteSize(); + final long byteSize = memoryLib.byteSize(memory); return (int) byteSize; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenMemcpyBigNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenMemcpyBigNode.java index d36db65d88d4..786c957fc6fe 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenMemcpyBigNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/EmscriptenMemcpyBigNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -65,7 +65,7 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn int num = (int) WasmArguments.getArgument(args, 2); WasmMemory memory = memory(frame); - memory.copyFrom(memory, src, dest, num); + memoryLib.copyFrom(memory, memory, src, dest, num); return 0; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/GetTimeOfDayNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/GetTimeOfDayNode.java index 4174c696478b..799435ca73d9 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/GetTimeOfDayNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/GetTimeOfDayNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -65,8 +65,8 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn long now = getCurrentTime(); WasmMemory memory = memory(frame); - memory.store_i32(this, ptr, (int) (now / 1000)); - memory.store_i32(this, ptr + 4, (int) (now % 1000 * 1000)); + memoryLib.store_i32(memory, this, ptr, (int) (now / 1000)); + memoryLib.store_i32(memory, this, ptr + 4, (int) (now % 1000 * 1000)); return 0; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/SetErrNoNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/SetErrNoNode.java index 17a07ca53cb5..e777b8eece7e 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/SetErrNoNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/emscripten/SetErrNoNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -64,7 +64,7 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn // TODO: Get address (3120) via call to `___errno_location` WebAssembly function. WasmMemory memory = memory(frame); - memory.store_i32(this, 3120, value); + memoryLib.store_i32(memory, this, 3120, value); return value; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsGetNode.java index f6fd9d56652f..14a78c4b4110 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -70,10 +70,10 @@ private int argsGet(WasmMemory memory, int argvAddress, int argvBuffAddress) { int argvPointer = argvAddress; int argvBuffPointer = argvBuffAddress; for (final String argument : arguments) { - memory.store_i32(this, argvPointer, argvBuffPointer); + memoryLib.store_i32(memory, this, argvPointer, argvBuffPointer); argvPointer += 4; argvBuffPointer += memory.writeString(this, argument, argvBuffPointer); - memory.store_i32_8(this, argvBuffPointer, (byte) 0); + memoryLib.store_i32_8(memory, this, argvBuffPointer, (byte) 0); ++argvBuffPointer; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsSizesGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsSizesGetNode.java index bd0dab18917f..d7ca64074e86 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsSizesGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiArgsSizesGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -74,8 +74,8 @@ private int argsSizesGet(WasmMemory memory, int argcAddress, int argvBufSizeAddr argvBufSize += 1; // extra byte needed for the trailing null character } - memory.store_i32(this, argcAddress, argc); - memory.store_i32(this, argvBufSizeAddress, argvBufSize); + memoryLib.store_i32(memory, this, argcAddress, argc); + memoryLib.store_i32(memory, this, argvBufSizeAddress, argvBufSize); return Errno.Success.ordinal(); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockResGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockResGetNode.java index 47df097a7cc3..5ed761848a81 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockResGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockResGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -78,7 +78,7 @@ private Object clockResGet(WasmMemory memory, int clockIdValue, int resultAddres switch (clockId) { case Realtime: case Monotonic: - memory.store_i64(this, resultAddress, CLOCK_RESOLUTION_NANOS); + memoryLib.store_i64(memory, this, resultAddress, CLOCK_RESOLUTION_NANOS); break; case ProcessCputimeId: case ThreadCputimeId: diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java index b79d39a3824d..f116ed5dd246 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -78,10 +78,10 @@ private Object clockTimeGet(WasmMemory memory, int clockIdValue, int resultAddre final Clockid clockId = Clockid.values()[clockIdValue]; switch (clockId) { case Realtime: - memory.store_i64(this, resultAddress, realtimeNow()); + memoryLib.store_i64(memory, this, resultAddress, realtimeNow()); break; case Monotonic: - memory.store_i64(this, resultAddress, monotonicNow()); + memoryLib.store_i64(memory, this, resultAddress, monotonicNow()); break; case ProcessCputimeId: case ThreadCputimeId: diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java index 544c0767d290..05e603bf8c33 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -72,10 +72,10 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn @SuppressFBWarnings(value = "DMI_RANDOM_USED_ONLY_ONCE", justification = "This is a testing class only") @CompilerDirectives.TruffleBoundary - private static int randomGet(WasmMemory memory, int buf, int size) { + private int randomGet(WasmMemory memory, int buf, int size) { byte[] randomData = new byte[size]; new Random(SEED).nextBytes(randomData); - memory.initialize(randomData, 0, buf, size); + memoryLib.initialize(memory, randomData, 0, buf, size); return Errno.Success.ordinal(); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironGetNode.java index b514edefb28a..ee640251e67d 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -72,10 +72,10 @@ private int environGet(WasmMemory memory, int envInitialPointer, int bufInitialP int envPointer = envInitialPointer; final Map env = getContext().environment().getEnvironment(); for (final Map.Entry entry : env.entrySet()) { - memory.store_i32(this, envPointer, bufPointer); + memoryLib.store_i32(memory, this, envPointer, bufPointer); envPointer += 4; bufPointer += memory.writeString(this, entry.getKey() + "=" + entry.getValue(), bufPointer); - memory.store_i32_8(this, bufPointer, (byte) 0); + memoryLib.store_i32_8(memory, this, bufPointer, (byte) 0); ++bufPointer; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironSizesGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironSizesGetNode.java index 872c57095cb3..92115fa9e3fc 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironSizesGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiEnvironSizesGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -75,8 +75,8 @@ private int environSizesGet(WasmMemory memory, int environCountAddress, int envi size += 1; // extra byte needed for the trailing null character } - memory.store_i32(this, environCountAddress, env.size()); - memory.store_i32(this, environSizeAddress, size); + memoryLib.store_i32(memory, this, environCountAddress, env.size()); + memoryLib.store_i32(memory, this, environSizeAddress, size); return Errno.Success.ordinal(); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java index 4af7258c2463..5aefe6c66c99 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -66,10 +66,10 @@ public Object executeWithContext(VirtualFrame frame, WasmContext context, WasmIn } @CompilerDirectives.TruffleBoundary - private static int randomGet(WasmMemory memory, int buf, int size) { + private int randomGet(WasmMemory memory, int buf, int size) { byte[] randomData = new byte[size]; ThreadLocalRandom.current().nextBytes(randomData); - memory.initialize(randomData, 0, buf, size); + memoryLib.initialize(memory, randomData, 0, buf, size); return Errno.Success.ordinal(); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java index b18375337b7b..33d5af687fa2 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -57,6 +57,7 @@ import java.util.concurrent.TimeUnit; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.wasi.WasiClockTimeGetNode; import org.graalvm.wasm.predefined.wasi.types.Dirent; import org.graalvm.wasm.predefined.wasi.types.Errno; @@ -306,7 +307,7 @@ public Errno pathOpen(Node node, WasmMemory memory, int dirFlags, int pathAddres if (isSet(childOflags, Oflags.Directory)) { if (hostChildFile.isDirectory()) { final int fd = fdManager.put(new DirectoryFd(fdManager, virtualChildFile, preopenedRoot, childFsRightsBase, childFsRightsInheriting, childFdFlags)); - memory.store_i32(node, fdAddress, fd); + WasmMemoryLibrary.getUncached().store_i32(memory, node, fdAddress, fd); return Errno.Success; } else { return Errno.Notdir; @@ -314,7 +315,7 @@ public Errno pathOpen(Node node, WasmMemory memory, int dirFlags, int pathAddres } else { try { final int fd = fdManager.put(new FileFd(hostChildFile, childOflags, childFsRightsBase, childFsRightsInheriting, childFdFlags)); - memory.store_i32(node, fdAddress, fd); + WasmMemoryLibrary.getUncached().store_i32(memory, node, fdAddress, fd); return Errno.Success; } catch (FileAlreadyExistsException e) { return Errno.Exist; @@ -344,6 +345,8 @@ public Errno readdir(Node node, WasmMemory memory, int bufAddress, int bufLength int bufEnd = bufAddress + bufLength; long currentEntry = 0; + WasmMemoryLibrary memories = WasmMemoryLibrary.getUncached(); + for (TruffleFile file : entries) { // Only write entries whose index is past the received "cookie" if (currentEntry >= cookie) { @@ -356,7 +359,7 @@ public Errno readdir(Node node, WasmMemory memory, int bufAddress, int bufLength byte[] dirent = FdUtils.writeDirentToByteArray(file, name.length, currentEntry + 1); for (int i = 0; bufPointer < bufEnd; i++, bufPointer++) { assert i < dirent.length; - memory.store_i32_8(node, bufPointer, dirent[i]); + memories.store_i32_8(memory, node, bufPointer, dirent[i]); } assert bufPointer == bufEnd; break; @@ -368,7 +371,7 @@ public Errno readdir(Node node, WasmMemory memory, int bufAddress, int bufLength // Truncate file name for (int i = 0; bufPointer < bufEnd; i++, bufPointer++) { assert i < name.length; - memory.store_i32_8(node, bufPointer, name[i]); + memories.store_i32_8(memory, node, bufPointer, name[i]); } assert bufPointer == bufEnd; break; @@ -376,7 +379,7 @@ public Errno readdir(Node node, WasmMemory memory, int bufAddress, int bufLength } currentEntry++; } - memory.store_i32(node, sizeAddress, bufPointer - bufAddress); + memories.store_i32(memory, node, sizeAddress, bufPointer - bufAddress); } catch (IOException e) { return Errno.Io; } @@ -400,7 +403,7 @@ public int pathReadLink(Node node, WasmMemory memory, int pathAddress, int pathL } final String content = virtualLink.getPath(); int bytesWritten = memory.writeString(node, content, buf, bufLen); - memory.store_i32(node, sizeAddress, bytesWritten); + WasmMemoryLibrary.getUncached().store_i32(memory, node, sizeAddress, bytesWritten); return Errno.Success.ordinal(); } catch (NotLinkException e) { return Errno.Nolink.ordinal(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java index 6db0f6dc3723..8b8e85673509 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,6 +44,7 @@ import com.oracle.truffle.api.TruffleFile; import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.wasi.types.Dirent; import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Fdstat; @@ -68,20 +69,21 @@ static Errno writeToStream(Node node, WasmMemory memory, OutputStream stream, in return Errno.Acces; } + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); int totalBytesWritten = 0; try { for (int i = 0; i < iovecCount; i++) { final int iovecAddress = iovecArrayAddress + i * Iovec.BYTES; - final int start = Iovec.readBuf(node, memory, iovecAddress); - final int len = Iovec.readBufLen(node, memory, iovecAddress); - memory.copyToStream(node, stream, start, len); + final int start = Iovec.readBuf(node, memoryLib, memory, iovecAddress); + final int len = Iovec.readBufLen(node, memoryLib, memory, iovecAddress); + memoryLib.copyToStream(memory, node, stream, start, len); totalBytesWritten += len; } } catch (IOException e) { return Errno.Io; } - memory.store_i32(node, sizeAddress, totalBytesWritten); + WasmMemoryLibrary.getUncached().store_i32(memory, node, sizeAddress, totalBytesWritten); return Errno.Success; } @@ -90,13 +92,14 @@ static Errno readFromStream(Node node, WasmMemory memory, InputStream stream, in return Errno.Acces; } + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); int totalBytesRead = 0; try { for (int i = 0; i < iovecCount; i++) { final int iovecAddress = iovecArrayAddress + i * Iovec.BYTES; - final int start = Iovec.readBuf(node, memory, iovecAddress); - final int len = Iovec.readBufLen(node, memory, iovecAddress); - final int bytesRead = memory.copyFromStream(node, stream, start, len); + final int start = Iovec.readBuf(node, memoryLib, memory, iovecAddress); + final int len = Iovec.readBufLen(node, memoryLib, memory, iovecAddress); + final int bytesRead = memoryLib.copyFromStream(memory, node, stream, start, len); if (bytesRead == -1) { break; } @@ -106,7 +109,7 @@ static Errno readFromStream(Node node, WasmMemory memory, InputStream stream, in return Errno.Io; } - memory.store_i32(node, sizeAddress, totalBytesRead); + WasmMemoryLibrary.getUncached().store_i32(memory, node, sizeAddress, totalBytesRead); return Errno.Success; } @@ -144,10 +147,11 @@ static Errno readFromStreamAt(Node node, WasmMemory memory, InputStream stream, * structure to memory. */ static Errno writeFdstat(Node node, WasmMemory memory, int address, Filetype type, short fsFlags, long fsRightsBase, long fsRightsInherting) { - Fdstat.writeFsFiletype(node, memory, address, type); - Fdstat.writeFsFlags(node, memory, address, fsFlags); - Fdstat.writeFsRightsBase(node, memory, address, fsRightsBase); - Fdstat.writeFsRightsInheriting(node, memory, address, fsRightsInherting); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + Fdstat.writeFsFiletype(node, memoryLib, memory, address, type); + Fdstat.writeFsFlags(node, memoryLib, memory, address, fsFlags); + Fdstat.writeFsRightsBase(node, memoryLib, memory, address, fsRightsBase); + Fdstat.writeFsRightsInheriting(node, memoryLib, memory, address, fsRightsInherting); return Errno.Success; } @@ -159,17 +163,18 @@ static Errno writeFdstat(Node node, WasmMemory memory, int address, Filetype typ static Errno writeFilestat(Node node, WasmMemory memory, int address, TruffleFile file) { // Write filestat structure // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-filestat-struct + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); try { - Filestat.writeFiletype(node, memory, address, getType(file)); - Filestat.writeSize(node, memory, address, file.getAttribute(TruffleFile.SIZE)); - Filestat.writeAtim(node, memory, address, file.getAttribute(TruffleFile.LAST_ACCESS_TIME).to(TimeUnit.NANOSECONDS)); - Filestat.writeMtim(node, memory, address, file.getAttribute(TruffleFile.LAST_MODIFIED_TIME).to(TimeUnit.NANOSECONDS)); + Filestat.writeFiletype(node, memoryLib, memory, address, getType(file)); + Filestat.writeSize(node, memoryLib, memory, address, file.getAttribute(TruffleFile.SIZE)); + Filestat.writeAtim(node, memoryLib, memory, address, file.getAttribute(TruffleFile.LAST_ACCESS_TIME).to(TimeUnit.NANOSECONDS)); + Filestat.writeMtim(node, memoryLib, memory, address, file.getAttribute(TruffleFile.LAST_MODIFIED_TIME).to(TimeUnit.NANOSECONDS)); try { - Filestat.writeDev(node, memory, address, file.getAttribute(TruffleFile.UNIX_DEV)); - Filestat.writeIno(node, memory, address, file.getAttribute(TruffleFile.UNIX_INODE)); - Filestat.writeNlink(node, memory, address, file.getAttribute(TruffleFile.UNIX_NLINK)); - Filestat.writeCtim(node, memory, address, file.getAttribute(TruffleFile.UNIX_CTIME).to(TimeUnit.NANOSECONDS)); + Filestat.writeDev(node, memoryLib, memory, address, file.getAttribute(TruffleFile.UNIX_DEV)); + Filestat.writeIno(node, memoryLib, memory, address, file.getAttribute(TruffleFile.UNIX_INODE)); + Filestat.writeNlink(node, memoryLib, memory, address, file.getAttribute(TruffleFile.UNIX_NLINK)); + Filestat.writeCtim(node, memoryLib, memory, address, file.getAttribute(TruffleFile.UNIX_CTIME).to(TimeUnit.NANOSECONDS)); } catch (UnsupportedOperationException e) { // GR-29297: these attributes are currently not supported on non-Unix platforms. } @@ -182,14 +187,15 @@ static Errno writeFilestat(Node node, WasmMemory memory, int address, TruffleFil } static int writeDirent(Node node, WasmMemory memory, int address, TruffleFile file, int nameLength, long offset) throws IOException { - Dirent.writeDNext(node, memory, address, offset); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + Dirent.writeDNext(node, memoryLib, memory, address, offset); try { - Dirent.writeDIno(node, memory, address, file.getAttribute(TruffleFile.UNIX_INODE)); + Dirent.writeDIno(node, memoryLib, memory, address, file.getAttribute(TruffleFile.UNIX_INODE)); } catch (UnsupportedOperationException e) { // GR-29297: these attributes are currently not supported on non-Unix platforms. } - Dirent.writeDNamlen(node, memory, address, nameLength); - Dirent.writeDType(node, memory, address, FdUtils.getType(file)); + Dirent.writeDNamlen(node, memoryLib, memory, address, nameLength); + Dirent.writeDType(node, memoryLib, memory, address, FdUtils.getType(file)); return Dirent.BYTES; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectoryFd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectoryFd.java index ca71d4299541..43c70bfb2e64 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectoryFd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectoryFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,6 +44,7 @@ import com.oracle.truffle.api.TruffleFile; import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Preopentype; import org.graalvm.wasm.predefined.wasi.types.Prestat; @@ -70,9 +71,10 @@ final class PreopenedDirectoryFd extends DirectoryFd { @Override public Errno prestatGet(Node node, WasmMemory memory, int prestatAddress) { - Prestat.writeTag(node, memory, prestatAddress, Preopentype.Dir); + WasmMemoryLibrary memoryLib = WasmMemoryLibrary.getUncached(); + Prestat.writeTag(node, memoryLib, memory, prestatAddress, Preopentype.Dir); final int prestatDirAddress = prestatAddress + Prestat.CONTENTSOFFSET; - PrestatDir.writePrNameLen(node, memory, prestatDirAddress, WasmMemory.encodedStringLength(virtualPath)); + PrestatDir.writePrNameLen(node, memoryLib, memory, prestatDirAddress, WasmMemory.encodedStringLength(virtualPath)); return Errno.Success; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/SeekableByteChannelFd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/SeekableByteChannelFd.java index 5664f25a0cb7..cd3367470642 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/SeekableByteChannelFd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/SeekableByteChannelFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -43,6 +43,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Fdflags; import org.graalvm.wasm.predefined.wasi.types.Filetype; @@ -153,7 +154,7 @@ public Errno seek(Node node, WasmMemory memory, long offset, Whence whence, int return Errno.Inval; } channel.position(newOffset); - memory.store_i64(node, newOffsetAddress, channel.position()); + WasmMemoryLibrary.getUncached().store_i64(memory, node, newOffsetAddress, channel.position()); } catch (IOException e) { return Errno.Io; } @@ -166,7 +167,7 @@ public Errno tell(Node node, WasmMemory memory, int offsetAddress) { return Errno.Notcapable; } try { - memory.store_i64(node, offsetAddress, channel.position()); + WasmMemoryLibrary.getUncached().store_i64(memory, node, offsetAddress, channel.position()); } catch (IOException e) { return Errno.Io; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Ciovec.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Ciovec.java index cbba481cf5c7..9a5ed8001cd6 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Ciovec.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Ciovec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** A region of memory for scatter/gather writes. */ public final class Ciovec { @@ -59,23 +60,23 @@ private Ciovec() { public static final int BYTES = 8; /** Reads the address of the buffer to be written. */ - public static int readBuf(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 0); + public static int readBuf(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 0); } /** Writes the address of the buffer to be written. */ - public static void writeBuf(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 0, value); + public static void writeBuf(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 0, value); } /** Reads the length of the buffer to be written. */ - public static int readBufLen(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 4); + public static int readBufLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 4); } /** Writes the length of the buffer to be written. */ - public static void writeBufLen(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 4, value); + public static void writeBufLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 4, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Dirent.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Dirent.java index be7f0e68b8ac..75b3b80f016a 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Dirent.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Dirent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -48,6 +48,7 @@ import com.oracle.truffle.api.memory.ByteArraySupport; import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** A directory entry. */ public final class Dirent { @@ -60,13 +61,13 @@ private Dirent() { public static final int BYTES = 24; /** Reads the offset of the next directory entry stored in this directory. */ - public static long readDNext(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 0); + public static long readDNext(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 0); } /** Writes the offset of the next directory entry stored in this directory. */ - public static void writeDNext(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 0, value); + public static void writeDNext(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 0, value); } /** Writes the offset of the next directory entry stored in this directory. */ @@ -75,13 +76,13 @@ public static void writeDNextToByteArray(byte[] buffer, int address, long value) } /** Reads the serial number of the file referred to by this directory entry. */ - public static long readDIno(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 8); + public static long readDIno(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 8); } /** Writes the serial number of the file referred to by this directory entry. */ - public static void writeDIno(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 8, value); + public static void writeDIno(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 8, value); } /** Writes the serial number of the file referred to by this directory entry. */ @@ -90,13 +91,13 @@ public static void writeDInoToByteArray(byte[] buffer, int address, long value) } /** Reads the length of the name of the directory entry. */ - public static int readDNamlen(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 16); + public static int readDNamlen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 16); } /** Writes the length of the name of the directory entry. */ - public static void writeDNamlen(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 16, value); + public static void writeDNamlen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 16, value); } /** Writes the length of the name of the directory entry. */ @@ -105,13 +106,13 @@ public static void writeDNamlen(byte[] buffer, int address, int value) { } /** Reads the type of the file referred to by this directory entry. */ - public static Filetype readDType(Node node, WasmMemory memory, int address) { - return Filetype.fromValue((byte) memory.load_i32_8u(node, address + 20)); + public static Filetype readDType(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Filetype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 20)); } /** Writes the type of the file referred to by this directory entry. */ - public static void writeDType(Node node, WasmMemory memory, int address, Filetype value) { - memory.store_i32_8(node, address + 20, value.toValue()); + public static void writeDType(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Filetype value) { + memoryLib.store_i32_8(memory, node, address + 20, value.toValue()); } /** Writes the type of the file referred to by this directory entry. */ diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Event.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Event.java index fd54d1d2341b..cfa98c97ccc1 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Event.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Event.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** An event that occurred. */ public final class Event { @@ -59,49 +60,49 @@ private Event() { public static final int BYTES = 32; /** Reads user-provided value that got attached to {@code subscription::userdata}. */ - public static long readUserdata(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 0); + public static long readUserdata(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 0); } /** Writes user-provided value that got attached to {@code subscription::userdata}. */ - public static void writeUserdata(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 0, value); + public static void writeUserdata(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 0, value); } /** Reads if non-zero, an error that occurred while processing the subscription request. */ - public static Errno readError(Node node, WasmMemory memory, int address) { - return Errno.fromValue((short) memory.load_i32_16u(node, address + 8)); + public static Errno readError(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Errno.fromValue((short) memoryLib.load_i32_16u(memory, node, address + 8)); } /** Writes if non-zero, an error that occurred while processing the subscription request. */ - public static void writeError(Node node, WasmMemory memory, int address, Errno value) { - memory.store_i32_16(node, address + 8, value.toValue()); + public static void writeError(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Errno value) { + memoryLib.store_i32_16(memory, node, address + 8, value.toValue()); } /** Reads the type of event that occured. */ - public static Eventtype readType(Node node, WasmMemory memory, int address) { - return Eventtype.fromValue((byte) memory.load_i32_8u(node, address + 10)); + public static Eventtype readType(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Eventtype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 10)); } /** Writes the type of event that occured. */ - public static void writeType(Node node, WasmMemory memory, int address, Eventtype value) { - memory.store_i32_8(node, address + 10, value.toValue()); + public static void writeType(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Eventtype value) { + memoryLib.store_i32_8(memory, node, address + 10, value.toValue()); } /** * Reads the contents of the event, if it is an {@code eventtype::fd_read} or * {@code eventtype::fd_write}. {@code eventtype::clock} events ignore this field. */ - public static int readFdReadwrite(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 16); + public static int readFdReadwrite(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 16); } /** * Writes the contents of the event, if it is an {@code eventtype::fd_read} or * {@code eventtype::fd_write}. {@code eventtype::clock} events ignore this field. */ - public static void writeFdReadwrite(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 16, value); + public static void writeFdReadwrite(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 16, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/EventFdReadwrite.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/EventFdReadwrite.java index 47d279abbd55..5ddf0f152e96 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/EventFdReadwrite.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/EventFdReadwrite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** * The contents of an {@code event} when type is {@code eventtype::fd_read} or @@ -62,23 +63,23 @@ private EventFdReadwrite() { public static final int BYTES = 16; /** Reads the number of bytes available for reading or writing. */ - public static long readNbytes(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 0); + public static long readNbytes(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 0); } /** Writes the number of bytes available for reading or writing. */ - public static void writeNbytes(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 0, value); + public static void writeNbytes(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 0, value); } /** Reads the state of the file descriptor. */ - public static short readFlags(Node node, WasmMemory memory, int address) { - return (short) memory.load_i32_16u(node, address + 8); + public static short readFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return (short) memoryLib.load_i32_16u(memory, node, address + 8); } /** Writes the state of the file descriptor. */ - public static void writeFlags(Node node, WasmMemory memory, int address, short value) { - memory.store_i32_16(node, address + 8, value); + public static void writeFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, short value) { + memoryLib.store_i32_16(memory, node, address + 8, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Fdstat.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Fdstat.java index 9aeb8bb11c74..694522fc9354 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Fdstat.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Fdstat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** File descriptor attributes. */ public final class Fdstat { @@ -59,49 +60,49 @@ private Fdstat() { public static final int BYTES = 24; /** Reads file type. */ - public static Filetype readFsFiletype(Node node, WasmMemory memory, int address) { - return Filetype.fromValue((byte) memory.load_i32_8u(node, address + 0)); + public static Filetype readFsFiletype(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Filetype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 0)); } /** Writes file type. */ - public static void writeFsFiletype(Node node, WasmMemory memory, int address, Filetype value) { - memory.store_i32_8(node, address + 0, value.toValue()); + public static void writeFsFiletype(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Filetype value) { + memoryLib.store_i32_8(memory, node, address + 0, value.toValue()); } /** Reads file descriptor flags. */ - public static short readFsFlags(Node node, WasmMemory memory, int address) { - return (short) memory.load_i32_16u(node, address + 2); + public static short readFsFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return (short) memoryLib.load_i32_16u(memory, node, address + 2); } /** Writes file descriptor flags. */ - public static void writeFsFlags(Node node, WasmMemory memory, int address, short value) { - memory.store_i32_16(node, address + 2, value); + public static void writeFsFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, short value) { + memoryLib.store_i32_16(memory, node, address + 2, value); } /** Reads rights that apply to this file descriptor. */ - public static long readFsRightsBase(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 8); + public static long readFsRightsBase(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 8); } /** Writes rights that apply to this file descriptor. */ - public static void writeFsRightsBase(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 8, value); + public static void writeFsRightsBase(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 8, value); } /** * Reads maximum set of rights that may be installed on new file descriptors that are created * through this file descriptor, e.g., through {@code path_open}. */ - public static long readFsRightsInheriting(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 16); + public static long readFsRightsInheriting(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 16); } /** * Writes maximum set of rights that may be installed on new file descriptors that are created * through this file descriptor, e.g., through {@code path_open}. */ - public static void writeFsRightsInheriting(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 16, value); + public static void writeFsRightsInheriting(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 16, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Filestat.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Filestat.java index e766fc4d5ab1..b3c3e89ba4c9 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Filestat.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Filestat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** File attributes. */ public final class Filestat { @@ -59,89 +60,89 @@ private Filestat() { public static final int BYTES = 64; /** Reads device id of device containing the file. */ - public static long readDev(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 0); + public static long readDev(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 0); } /** Writes device id of device containing the file. */ - public static void writeDev(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 0, value); + public static void writeDev(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 0, value); } /** Reads file serial number. */ - public static long readIno(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 8); + public static long readIno(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 8); } /** Writes file serial number. */ - public static void writeIno(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 8, value); + public static void writeIno(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 8, value); } /** Reads file type. */ - public static Filetype readFiletype(Node node, WasmMemory memory, int address) { - return Filetype.fromValue((byte) memory.load_i32_8u(node, address + 16)); + public static Filetype readFiletype(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Filetype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 16)); } /** Writes file type. */ - public static void writeFiletype(Node node, WasmMemory memory, int address, Filetype value) { - memory.store_i32_8(node, address + 16, value.toValue()); + public static void writeFiletype(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Filetype value) { + memoryLib.store_i32_8(memory, node, address + 16, value.toValue()); } /** Reads number of hard links to the file. */ - public static long readNlink(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 24); + public static long readNlink(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 24); } /** Writes number of hard links to the file. */ - public static void writeNlink(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 24, value); + public static void writeNlink(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 24, value); } /** * Reads for regular files, the file size in bytes. for symbolic links, the length in bytes of * the pathname contained in the symbolic link. */ - public static long readSize(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 32); + public static long readSize(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 32); } /** * Writes for regular files, the file size in bytes. for symbolic links, the length in bytes of * the pathname contained in the symbolic link. */ - public static void writeSize(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 32, value); + public static void writeSize(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 32, value); } /** Reads last data access timestamp. */ - public static long readAtim(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 40); + public static long readAtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 40); } /** Writes last data access timestamp. */ - public static void writeAtim(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 40, value); + public static void writeAtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 40, value); } /** Reads last data modification timestamp. */ - public static long readMtim(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 48); + public static long readMtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 48); } /** Writes last data modification timestamp. */ - public static void writeMtim(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 48, value); + public static void writeMtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 48, value); } /** Reads last file status change timestamp. */ - public static long readCtim(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 56); + public static long readCtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 56); } /** Writes last file status change timestamp. */ - public static void writeCtim(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 56, value); + public static void writeCtim(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 56, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Iovec.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Iovec.java index 07a5eb95d085..195e4aa338c5 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Iovec.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Iovec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** A region of memory for scatter/gather reads. */ public final class Iovec { @@ -59,23 +60,23 @@ private Iovec() { public static final int BYTES = 8; /** Reads the address of the buffer to be filled. */ - public static int readBuf(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 0); + public static int readBuf(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 0); } /** Writes the address of the buffer to be filled. */ - public static void writeBuf(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 0, value); + public static void writeBuf(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 0, value); } /** Reads the length of the buffer to be filled. */ - public static int readBufLen(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 4); + public static int readBufLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 4); } /** Writes the length of the buffer to be filled. */ - public static void writeBufLen(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 4, value); + public static void writeBufLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 4, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Prestat.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Prestat.java index 24975c663163..fb1ddc41653b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Prestat.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Prestat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** Information about a pre-opened capability. */ public final class Prestat { @@ -59,13 +60,13 @@ private Prestat() { public static final int CONTENTSOFFSET = 4; /** Reads union tag. */ - public static Preopentype readTag(Node node, WasmMemory memory, int address) { - return Preopentype.fromValue((byte) memory.load_i32_8u(node, address + 0)); + public static Preopentype readTag(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Preopentype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 0)); } /** Writes union tag. */ - public static void writeTag(Node node, WasmMemory memory, int address, Preopentype tag) { - memory.store_i32_8(node, address + 0, tag.toValue()); + public static void writeTag(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Preopentype tag) { + memoryLib.store_i32_8(memory, node, address + 0, tag.toValue()); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/PrestatDir.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/PrestatDir.java index c132106daa2c..c21c2a7724b4 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/PrestatDir.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/PrestatDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** The contents of a $prestat when type is {@code preopentype::dir}. */ public final class PrestatDir { @@ -59,13 +60,13 @@ private PrestatDir() { public static final int BYTES = 4; /** Reads the length of the directory name for use with {@code fd_prestat_dir_name}. */ - public static int readPrNameLen(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 0); + public static int readPrNameLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 0); } /** Writes the length of the directory name for use with {@code fd_prestat_dir_name}. */ - public static void writePrNameLen(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 0, value); + public static void writePrNameLen(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 0, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Subscription.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Subscription.java index 9a08817b8ecd..1b354db19f17 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Subscription.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/Subscription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** Subscription to an event. */ public final class Subscription { @@ -62,26 +63,26 @@ private Subscription() { * Reads user-provided value that is attached to the subscription in the implementation and * returned through {@code event::userdata}. */ - public static long readUserdata(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 0); + public static long readUserdata(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 0); } /** * Writes user-provided value that is attached to the subscription in the implementation and * returned through {@code event::userdata}. */ - public static void writeUserdata(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 0, value); + public static void writeUserdata(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 0, value); } /** Reads the type of the event to which to subscribe, and its contents. */ - public static int readU(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 8); + public static int readU(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 8); } /** Writes the type of the event to which to subscribe, and its contents. */ - public static void writeU(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 8, value); + public static void writeU(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 8, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionClock.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionClock.java index 12a58bd06047..87ccecde5975 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionClock.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionClock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** The contents of a {@code subscription} when type is {@code eventtype::clock}. */ public final class SubscriptionClock { @@ -59,49 +60,49 @@ private SubscriptionClock() { public static final int BYTES = 32; /** Reads the clock against which to compare the timestamp. */ - public static Clockid readId(Node node, WasmMemory memory, int address) { - return Clockid.fromValue(memory.load_i32(node, address + 0)); + public static Clockid readId(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Clockid.fromValue(memoryLib.load_i32(memory, node, address + 0)); } /** Writes the clock against which to compare the timestamp. */ - public static void writeId(Node node, WasmMemory memory, int address, Clockid value) { - memory.store_i32(node, address + 0, value.toValue()); + public static void writeId(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Clockid value) { + memoryLib.store_i32(memory, node, address + 0, value.toValue()); } /** Reads the absolute or relative timestamp. */ - public static long readTimeout(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 8); + public static long readTimeout(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 8); } /** Writes the absolute or relative timestamp. */ - public static void writeTimeout(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 8, value); + public static void writeTimeout(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 8, value); } /** * Reads the amount of time that the implementation may wait additionally to coalesce with other * events. */ - public static long readPrecision(Node node, WasmMemory memory, int address) { - return memory.load_i64(node, address + 16); + public static long readPrecision(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i64(memory, node, address + 16); } /** * Writes the amount of time that the implementation may wait additionally to coalesce with * other events. */ - public static void writePrecision(Node node, WasmMemory memory, int address, long value) { - memory.store_i64(node, address + 16, value); + public static void writePrecision(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, long value) { + memoryLib.store_i64(memory, node, address + 16, value); } /** Reads flags specifying whether the timeout is absolute or relative. */ - public static short readFlags(Node node, WasmMemory memory, int address) { - return (short) memory.load_i32_16u(node, address + 24); + public static short readFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return (short) memoryLib.load_i32_16u(memory, node, address + 24); } /** Writes flags specifying whether the timeout is absolute or relative. */ - public static void writeFlags(Node node, WasmMemory memory, int address, short value) { - memory.store_i32_16(node, address + 24, value); + public static void writeFlags(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, short value) { + memoryLib.store_i32_16(memory, node, address + 24, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionFdReadwrite.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionFdReadwrite.java index c5d4bd9c6da5..8ba80d0282ec 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionFdReadwrite.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionFdReadwrite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** * The contents of a {@code subscription} when type is type is {@code eventtype::fd_read} or @@ -62,15 +63,15 @@ private SubscriptionFdReadwrite() { public static final int BYTES = 4; /** Reads the file descriptor on which to wait for it to become ready for reading or writing. */ - public static int readFileDescriptor(Node node, WasmMemory memory, int address) { - return memory.load_i32(node, address + 0); + public static int readFileDescriptor(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return memoryLib.load_i32(memory, node, address + 0); } /** * Writes the file descriptor on which to wait for it to become ready for reading or writing. */ - public static void writeFileDescriptor(Node node, WasmMemory memory, int address, int value) { - memory.store_i32(node, address + 0, value); + public static void writeFileDescriptor(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, int value) { + memoryLib.store_i32(memory, node, address + 0, value); } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionU.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionU.java index 437b86d284d1..7465e5bec6fe 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionU.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/types/SubscriptionU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.memory.WasmMemoryLibrary; /** The contents of a {@code subscription}. */ public final class SubscriptionU { @@ -59,13 +60,13 @@ private SubscriptionU() { public static final int CONTENTSOFFSET = 8; /** Reads union tag. */ - public static Eventtype readTag(Node node, WasmMemory memory, int address) { - return Eventtype.fromValue((byte) memory.load_i32_8u(node, address + 0)); + public static Eventtype readTag(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address) { + return Eventtype.fromValue((byte) memoryLib.load_i32_8u(memory, node, address + 0)); } /** Writes union tag. */ - public static void writeTag(Node node, WasmMemory memory, int address, Eventtype tag) { - memory.store_i32_8(node, address + 0, tag.toValue()); + public static void writeTag(Node node, WasmMemoryLibrary memoryLib, WasmMemory memory, int address, Eventtype tag) { + memoryLib.store_i32_8(memory, node, address + 0, tag.toValue()); } }