Skip to content

Commit

Permalink
Introduce internal context option for DirectByteBuffer memory access
Browse files Browse the repository at this point in the history
  • Loading branch information
jirkamarsik committed Jan 22, 2025
1 parent 46eb7a7 commit a0e1a8c
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -472,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
Original file line number Diff line number Diff line change
Expand Up @@ -1005,17 +1005,18 @@ private void ensureMemoryCapacity(int index) {
}
}

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();
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, false, false, useUnsafeMemory);
wasmMemory = WasmMemoryFactory.createMemory(0, 0, false, false, useUnsafeMemory, directByteBufferMemoryAccess);
} else {
wasmMemory = WasmMemoryFactory.createMemory(declaredMinSize, declaredMaxSize, 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -88,13 +89,20 @@ 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);
}

private void checkOptionDependencies() {
if (memory64 && !unsafeMemory) {
failDependencyCheck("Memory64", "UseUnsafeMemory");
}
if (directByteBufferMemoryAccess && !unsafeMemory) {
failDependencyCheck("DirectByteBufferMemoryAccess", "UseUnsafeMemory");
}
}

private boolean readBooleanOption(OptionKey<Boolean> key) {
Expand Down Expand Up @@ -157,6 +165,10 @@ public boolean constantRandomGet() {
return constantRandomGet;
}

public boolean directByteBufferMemoryAccess() {
return directByteBufferMemoryAccess;
}

public String debugCompDirectory() {
return debugCompDirectory;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static List<LinkAction> recreateLinkActions(WasmModule module) {
final ModuleLimits limits = instance.module().limits();
limits.checkMemoryInstanceSize(memoryMinSize, memoryIndexType64);
final WasmMemory wasmMemory = WasmMemoryFactory.createMemory(memoryMinSize, memoryMaxSize, memoryIndexType64, memoryShared,
context.getContextOptions().useUnsafeMemory());
context.getContextOptions().useUnsafeMemory(), context.getContextOptions().directByteBufferMemoryAccess());
final int address = context.memories().register(wasmMemory);
final WasmMemory allocatedMemory = context.memories().memory(address);
instance.setMemory(memoryIndex, allocatedMemory);
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 @@ -113,6 +113,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<Boolean> 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<Boolean> DirectByteBufferMemoryAccess = new OptionKey<>(false);

@Option(help = "Test dir used for testing the debugger.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "<dir>") //
public static final OptionKey<String> DebugCompDirectory = new OptionKey<>("");
}
Original file line number Diff line number Diff line change
Expand Up @@ -716,12 +716,13 @@ 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, WasmMemoryFactory.getMaximumAllowedSize(useUnsafeMemory)) > 0) {
} else if (Long.compareUnsigned(initial, WasmMemoryFactory.getMaximumAllowedSize(shared, useUnsafeMemory, directByteBufferMemoryAccess)) > 0) {
throw new WasmJsApiException(WasmJsApiException.Kind.RangeError, "Min memory size exceeds implementation limit");
}
return WasmMemoryFactory.createMemory(initial, maximum, false, shared, useUnsafeMemory);
return WasmMemoryFactory.createMemory(initial, maximum, false, shared, useUnsafeMemory, directByteBufferMemoryAccess);
}

private static Object memGrow(Object[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,39 +45,32 @@
import static org.graalvm.wasm.Assert.assertTrue;

public class WasmMemoryFactory {
public static WasmMemory createMemory(long declaredMinSize, long declaredMaxSize, 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) {
return new UnsafeWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared);
} else {
if (declaredMaxSize > ByteArrayWasmMemory.MAX_ALLOWED_SIZE) {
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 {
return new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared);
}
}
return new ByteArrayWasmMemory(declaredMinSize, declaredMaxSize, indexType64, shared);
}

public static Class<? extends WasmMemory> getMemoryImplementation(long declaredMaxSize, boolean unsafeMemory) {
public static long getMaximumAllowedSize(boolean shared, boolean unsafeMemory, boolean directByteBufferMemoryAccess) {
if (unsafeMemory) {
return UnsafeWasmMemory.class;
} else {
if (declaredMaxSize > ByteArrayWasmMemory.MAX_ALLOWED_SIZE) {
return NativeWasmMemory.class;
if (directByteBufferMemoryAccess || shared) {
return UnsafeWasmMemory.MAX_ALLOWED_SIZE;
} else {
return ByteArrayWasmMemory.class;
return NativeWasmMemory.MAX_ALLOWED_SIZE;
}
}
}

public static long getMaximumAllowedSize(boolean unsafeMemory) {
if (unsafeMemory) {
return UnsafeWasmMemory.MAX_ALLOWED_SIZE;
} else {
return NativeWasmMemory.MAX_ALLOWED_SIZE;
}
return ByteArrayWasmMemory.MAX_ALLOWED_SIZE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit a0e1a8c

Please sign in to comment.