Skip to content

Commit

Permalink
[GR-57386] [GR-58964] Increase Wasm memory limits.
Browse files Browse the repository at this point in the history
PullRequest: graal/18716
  • Loading branch information
jirkamarsik committed Jan 23, 2025
2 parents af67cbe + 30c713e commit f6e5249
Show file tree
Hide file tree
Showing 61 changed files with 1,939 additions and 1,546 deletions.
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -235,7 +236,7 @@ private void runInContext(WasmCase testCase, Context context, List<Source> 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();
Expand Down Expand Up @@ -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);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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());
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,19 @@
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;

@RunWith(Parameterized.class)
public class WasmImplementationLimitationsSuite {
@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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);
}
}

Expand Down
32 changes: 24 additions & 8 deletions wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/Linker.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -99,14 +100,17 @@
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;
import com.oracle.truffle.api.CompilerDirectives;
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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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<Sym> dependencies = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit f6e5249

Please sign in to comment.