mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8254693: Add Panama feature to pass heap segments to native code
Reviewed-by: mcimadamore, lucy, vlivanov
This commit is contained in:
parent
c80e691adf
commit
9c98270737
73 changed files with 1990 additions and 960 deletions
|
@ -669,8 +669,13 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* might attempt to access the contents of the segment. As such, one of the
|
||||
* exceptions specified by the {@link MemorySegment#get(ValueLayout.OfByte, long)} or
|
||||
* the {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)}
|
||||
* methods may be thrown. The returned method handle will additionally throw
|
||||
* {@link NullPointerException} if any argument passed to it is {@code null}.
|
||||
* methods may be thrown. If an argument is a {@link MemorySegment} whose
|
||||
* corresponding layout is an {@linkplain AddressLayout address layout}, the linker
|
||||
* will throw an {@link IllegalArgumentException} if the segment is a heap memory
|
||||
* segment, unless heap memory segments are explicitly allowed through the
|
||||
* {@link Linker.Option#critical(boolean)} linker option. The returned method handle
|
||||
* will additionally throw {@link NullPointerException} if any argument passed to it
|
||||
* is {@code null}.
|
||||
*
|
||||
* @param function the function descriptor of the target foreign function
|
||||
* @param options the linker options associated with this linkage request
|
||||
|
@ -914,9 +919,23 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* <p>
|
||||
* Using this linker option when linking non-critical functions is likely to have
|
||||
* adverse effects, such as loss of performance or JVM crashes.
|
||||
* <p>
|
||||
* Critical functions can optionally allow access to the Java heap. This allows
|
||||
* clients to pass heap memory segments as addresses, where normally only off-heap
|
||||
* memory segments would be allowed. The memory region inside the Java heap is
|
||||
* exposed through a temporary native address that is valid for the duration of
|
||||
* the function call. Use of this mechanism is therefore only recommended when a
|
||||
* function needs to do short-lived access to Java heap memory, and copying the
|
||||
* relevant data to an off-heap memory segment would be prohibitive in terms of
|
||||
* performance.
|
||||
*
|
||||
* @param allowHeapAccess whether the linked function should allow access to the
|
||||
* Java heap.
|
||||
*/
|
||||
static Option critical() {
|
||||
return LinkerOptions.Critical.INSTANCE;
|
||||
static Option critical(boolean allowHeapAccess) {
|
||||
return allowHeapAccess
|
||||
? LinkerOptions.Critical.ALLOW_HEAP
|
||||
: LinkerOptions.Critical.DONT_ALLOW_HEAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,8 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
|||
|| pType == int.class
|
||||
|| pType == float.class
|
||||
|| pType == double.class
|
||||
|| pType == void.class);
|
||||
|| pType == void.class
|
||||
|| pType == Object.class);
|
||||
}
|
||||
|
||||
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package jdk.internal.foreign.abi;
|
||||
|
||||
import jdk.internal.foreign.AbstractMemorySegmentImpl;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.foreign.abi.BindingInterpreter.LoadFunc;
|
||||
import jdk.internal.foreign.abi.BindingInterpreter.StoreFunc;
|
||||
|
@ -201,7 +202,7 @@ public sealed interface Binding {
|
|||
LoadFunc loadFunc, SegmentAllocator allocator);
|
||||
|
||||
private static void checkType(Class<?> type) {
|
||||
if (!type.isPrimitive() || type == void.class)
|
||||
if (type != Object.class && (!type.isPrimitive() || type == void.class))
|
||||
throw new IllegalArgumentException("Illegal type: " + type);
|
||||
}
|
||||
|
||||
|
@ -267,8 +268,21 @@ public sealed interface Binding {
|
|||
return new BoxAddress(byteSize, 1, true);
|
||||
}
|
||||
|
||||
static UnboxAddress unboxAddress() {
|
||||
return UnboxAddress.INSTANCE;
|
||||
// alias
|
||||
static SegmentOffset unboxAddress() {
|
||||
return segmentOffsetNoAllowHeap();
|
||||
}
|
||||
|
||||
static SegmentBase segmentBase() {
|
||||
return SegmentBase.INSTANCE;
|
||||
}
|
||||
|
||||
static SegmentOffset segmentOffsetAllowHeap() {
|
||||
return SegmentOffset.INSTANCE_ALLOW_HEAP;
|
||||
}
|
||||
|
||||
static SegmentOffset segmentOffsetNoAllowHeap() {
|
||||
return SegmentOffset.INSTANCE_NO_ALLOW_HEAP;
|
||||
}
|
||||
|
||||
static Dup dup() {
|
||||
|
@ -413,6 +427,21 @@ public sealed interface Binding {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Binding.Builder segmentBase() {
|
||||
bindings.add(Binding.segmentBase());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Binding.Builder segmentOffsetAllowHeap() {
|
||||
bindings.add(Binding.segmentOffsetAllowHeap());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Binding.Builder segmentOffsetNoAllowHeap() {
|
||||
bindings.add(Binding.segmentOffsetNoAllowHeap());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Binding.Builder dup() {
|
||||
bindings.add(Binding.dup());
|
||||
return this;
|
||||
|
@ -448,8 +477,10 @@ public sealed interface Binding {
|
|||
|
||||
/**
|
||||
* VM_STORE([storage location], [type])
|
||||
* Pops a [type] from the operand stack, and moves it to [storage location]
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
* Pops a [type] from the operand stack, and moves it to [storage location]
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double.
|
||||
* [storage location] may be 'null', indicating that this value should be passed
|
||||
* to the VM stub, but does not have an explicit target register (e.g. oop offsets)
|
||||
*/
|
||||
record VMStore(VMStorage storage, Class<?> type) implements Move {
|
||||
|
||||
|
@ -469,8 +500,8 @@ public sealed interface Binding {
|
|||
|
||||
/**
|
||||
* VM_LOAD([storage location], [type])
|
||||
* Loads a [type] from [storage location], and pushes it onto the operand stack.
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
* Loads a [type] from [storage location], and pushes it onto the operand stack.
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
*/
|
||||
record VMLoad(VMStorage storage, Class<?> type) implements Move {
|
||||
|
||||
|
@ -493,9 +524,9 @@ public sealed interface Binding {
|
|||
|
||||
/**
|
||||
* BUFFER_STORE([offset into memory region], [type], [width])
|
||||
* Pops a [type] from the operand stack, then pops a MemorySegment from the operand stack.
|
||||
* Stores [width] bytes of the value contained in the [type] to [offset into memory region].
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
* Pops a [type] from the operand stack, then pops a MemorySegment from the operand stack.
|
||||
* Stores [width] bytes of the value contained in the [type] to [offset into memory region].
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
*/
|
||||
record BufferStore(long offset, Class<?> type, int byteWidth) implements Dereference {
|
||||
|
||||
|
@ -550,9 +581,9 @@ public sealed interface Binding {
|
|||
|
||||
/**
|
||||
* BUFFER_LOAD([offset into memory region], [type], [width])
|
||||
* Pops a MemorySegment from the operand stack,
|
||||
* and then loads [width] bytes from it at [offset into memory region], into a [type].
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
* Pops a MemorySegment from the operand stack,
|
||||
* and then loads [width] bytes from it at [offset into memory region], into a [type].
|
||||
* The [type] must be one of byte, short, char, int, long, float, or double
|
||||
*/
|
||||
record BufferLoad(long offset, Class<?> type, int byteWidth) implements Dereference {
|
||||
|
||||
|
@ -606,8 +637,8 @@ public sealed interface Binding {
|
|||
/**
|
||||
* COPY([size], [alignment])
|
||||
* Creates a new MemorySegment with the given [size] and [alignment],
|
||||
* and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
|
||||
* and pushes the new buffer onto the operand stack
|
||||
* and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
|
||||
* and pushes the new buffer onto the operand stack
|
||||
*/
|
||||
record Copy(long size, long alignment) implements Binding {
|
||||
private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment, SegmentAllocator allocator) {
|
||||
|
@ -653,12 +684,37 @@ public sealed interface Binding {
|
|||
}
|
||||
|
||||
/**
|
||||
* UNBOX_ADDRESS()
|
||||
* Pops a 'MemoryAddress' from the operand stack, converts it to a 'long',
|
||||
* with the given size, and pushes that onto the operand stack
|
||||
* SEGMENT_BASE()
|
||||
* Pops a MemorySegment from the stack, retrieves the heap base object from it, or null if there is none
|
||||
* (See: AbstractMemorySegmentImpl::unsafeGetBase), and pushes the result onto the operand stack.
|
||||
*/
|
||||
record UnboxAddress() implements Binding {
|
||||
static final UnboxAddress INSTANCE = new UnboxAddress();
|
||||
record SegmentBase() implements Binding {
|
||||
static final SegmentBase INSTANCE = new SegmentBase();
|
||||
|
||||
@Override
|
||||
public void verify(Deque<Class<?>> stack) {
|
||||
Class<?> actualType = stack.pop();
|
||||
SharedUtils.checkType(actualType, MemorySegment.class);
|
||||
stack.push(Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpret(Deque<Object> stack, StoreFunc storeFunc,
|
||||
LoadFunc loadFunc, SegmentAllocator allocator) {
|
||||
stack.push(((AbstractMemorySegmentImpl)stack.pop()).unsafeGetBase());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SEGMENT_OFFSET([allowHeap])
|
||||
* Pops a MemorySegment from the stack, retrieves the offset from it,
|
||||
* (See: AbstractMemorySegmentImpl::unsafeGetOffset), and pushes the result onto the operand stack.
|
||||
* Note that for heap segments, the offset is a virtual address into the heap base object.
|
||||
* If [allowHeap] is 'false' an exception will be thrown for heap segments (See SharedUtils::checkNative).
|
||||
*/
|
||||
record SegmentOffset(boolean allowHeap) implements Binding {
|
||||
static final SegmentOffset INSTANCE_NO_ALLOW_HEAP = new SegmentOffset(false);
|
||||
static final SegmentOffset INSTANCE_ALLOW_HEAP = new SegmentOffset(true);
|
||||
|
||||
@Override
|
||||
public void verify(Deque<Class<?>> stack) {
|
||||
|
@ -670,14 +726,18 @@ public sealed interface Binding {
|
|||
@Override
|
||||
public void interpret(Deque<Object> stack, StoreFunc storeFunc,
|
||||
LoadFunc loadFunc, SegmentAllocator allocator) {
|
||||
stack.push(SharedUtils.unboxSegment((MemorySegment)stack.pop()));
|
||||
MemorySegment operand = (MemorySegment) stack.pop();
|
||||
if (!allowHeap) {
|
||||
SharedUtils.checkNative(operand);
|
||||
}
|
||||
stack.push(((AbstractMemorySegmentImpl)operand).unsafeGetOffset());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BOX_ADDRESS()
|
||||
* Pops a 'long' from the operand stack, converts it to a 'MemorySegment', with the given size and memory scope
|
||||
* (either the context scope, or the global scope), and pushes that onto the operand stack.
|
||||
* Pops a 'long' from the operand stack, converts it to a 'MemorySegment', with the given size and memory scope
|
||||
* (either the context scope, or the global scope), and pushes that onto the operand stack.
|
||||
*/
|
||||
record BoxAddress(long size, long align, boolean needsScope) implements Binding {
|
||||
|
||||
|
|
|
@ -27,12 +27,13 @@ package jdk.internal.foreign.abi;
|
|||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class BindingInterpreter {
|
||||
|
||||
static void unbox(Object arg, List<Binding> bindings, StoreFunc storeFunc, SegmentAllocator allocator) {
|
||||
Deque<Object> stack = new ArrayDeque<>();
|
||||
Deque<Object> stack = new LinkedList<>(); // Use LinkedList as a null-friendly Deque for null segment bases
|
||||
|
||||
stack.push(arg);
|
||||
for (Binding b : bindings) {
|
||||
|
|
|
@ -39,9 +39,10 @@ import jdk.internal.foreign.abi.Binding.BufferStore;
|
|||
import jdk.internal.foreign.abi.Binding.Cast;
|
||||
import jdk.internal.foreign.abi.Binding.Copy;
|
||||
import jdk.internal.foreign.abi.Binding.Dup;
|
||||
import jdk.internal.foreign.abi.Binding.SegmentBase;
|
||||
import jdk.internal.foreign.abi.Binding.SegmentOffset;
|
||||
import jdk.internal.foreign.abi.Binding.ShiftLeft;
|
||||
import jdk.internal.foreign.abi.Binding.ShiftRight;
|
||||
import jdk.internal.foreign.abi.Binding.UnboxAddress;
|
||||
import jdk.internal.foreign.abi.Binding.VMLoad;
|
||||
import jdk.internal.foreign.abi.Binding.VMStore;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
@ -103,7 +104,9 @@ public class BindingSpecializer {
|
|||
private static final MethodTypeDesc MTD_SCOPE = MethodTypeDesc.of(CD_MemorySegment_Scope);
|
||||
private static final MethodTypeDesc MTD_SESSION_IMPL = MethodTypeDesc.of(CD_MemorySessionImpl);
|
||||
private static final MethodTypeDesc MTD_CLOSE = MTD_void;
|
||||
private static final MethodTypeDesc MTD_UNBOX_SEGMENT = MethodTypeDesc.of(CD_long, CD_MemorySegment);
|
||||
private static final MethodTypeDesc MTD_CHECK_NATIVE = MethodTypeDesc.of(CD_void, CD_MemorySegment);
|
||||
private static final MethodTypeDesc MTD_UNSAFE_GET_BASE = MethodTypeDesc.of(CD_Object);
|
||||
private static final MethodTypeDesc MTD_UNSAFE_GET_OFFSET = MethodTypeDesc.of(CD_long);
|
||||
private static final MethodTypeDesc MTD_COPY = MethodTypeDesc.of(CD_void, CD_MemorySegment, CD_long, CD_MemorySegment, CD_long, CD_long);
|
||||
private static final MethodTypeDesc MTD_LONG_TO_ADDRESS_NO_SCOPE = MethodTypeDesc.of(CD_MemorySegment, CD_long, CD_long, CD_long);
|
||||
private static final MethodTypeDesc MTD_LONG_TO_ADDRESS_SCOPE = MethodTypeDesc.of(CD_MemorySegment, CD_long, CD_long, CD_long, CD_MemorySessionImpl);
|
||||
|
@ -456,18 +459,19 @@ public class BindingSpecializer {
|
|||
private void doBindings(List<Binding> bindings) {
|
||||
for (Binding binding : bindings) {
|
||||
switch (binding) {
|
||||
case VMStore vmStore -> emitVMStore(vmStore);
|
||||
case VMLoad vmLoad -> emitVMLoad(vmLoad);
|
||||
case BufferStore bufferStore -> emitBufferStore(bufferStore);
|
||||
case BufferLoad bufferLoad -> emitBufferLoad(bufferLoad);
|
||||
case Copy copy -> emitCopyBuffer(copy);
|
||||
case Allocate allocate -> emitAllocBuffer(allocate);
|
||||
case BoxAddress boxAddress -> emitBoxAddress(boxAddress);
|
||||
case UnboxAddress unused -> emitUnboxAddress();
|
||||
case Dup unused -> emitDupBinding();
|
||||
case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft);
|
||||
case ShiftRight shiftRight -> emitShiftRight(shiftRight);
|
||||
case Cast cast -> emitCast(cast);
|
||||
case VMStore vmStore -> emitVMStore(vmStore);
|
||||
case VMLoad vmLoad -> emitVMLoad(vmLoad);
|
||||
case BufferStore bufferStore -> emitBufferStore(bufferStore);
|
||||
case BufferLoad bufferLoad -> emitBufferLoad(bufferLoad);
|
||||
case Copy copy -> emitCopyBuffer(copy);
|
||||
case Allocate allocate -> emitAllocBuffer(allocate);
|
||||
case BoxAddress boxAddress -> emitBoxAddress(boxAddress);
|
||||
case SegmentBase unused -> emitSegmentBase();
|
||||
case SegmentOffset segmentOffset -> emitSegmentOffset(segmentOffset);
|
||||
case Dup unused -> emitDupBinding();
|
||||
case ShiftLeft shiftLeft -> emitShiftLeft(shiftLeft);
|
||||
case ShiftRight shiftRight -> emitShiftRight(shiftRight);
|
||||
case Cast cast -> emitCast(cast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -775,9 +779,23 @@ public class BindingSpecializer {
|
|||
pushType(toType);
|
||||
}
|
||||
|
||||
private void emitUnboxAddress() {
|
||||
private void emitSegmentBase() {
|
||||
popType(MemorySegment.class);
|
||||
cb.invokestatic(CD_SharedUtils, "unboxSegment", MTD_UNBOX_SEGMENT);
|
||||
cb.checkcast(CD_AbstractMemorySegmentImpl);
|
||||
cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetBase", MTD_UNSAFE_GET_BASE);
|
||||
pushType(Object.class);
|
||||
}
|
||||
|
||||
private void emitSegmentOffset(SegmentOffset segmentOffset) {
|
||||
popType(MemorySegment.class);
|
||||
|
||||
if (!segmentOffset.allowHeap()) {
|
||||
cb.dup();
|
||||
cb.invokestatic(CD_SharedUtils, "checkNative", MTD_CHECK_NATIVE);
|
||||
}
|
||||
cb.checkcast(CD_AbstractMemorySegmentImpl);
|
||||
cb.invokevirtual(CD_AbstractMemorySegmentImpl, "unsafeGetOffset", MTD_UNSAFE_GET_OFFSET);
|
||||
|
||||
pushType(long.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,16 +25,17 @@
|
|||
package jdk.internal.foreign.abi;
|
||||
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.foreign.abi.Binding.Allocate;
|
||||
import jdk.internal.foreign.abi.Binding.*;
|
||||
import jdk.internal.foreign.abi.Binding.BoxAddress;
|
||||
import jdk.internal.foreign.abi.Binding.BufferLoad;
|
||||
import jdk.internal.foreign.abi.Binding.BufferStore;
|
||||
import jdk.internal.foreign.abi.Binding.Cast;
|
||||
import jdk.internal.foreign.abi.Binding.Copy;
|
||||
import jdk.internal.foreign.abi.Binding.Dup;
|
||||
import jdk.internal.foreign.abi.Binding.SegmentBase;
|
||||
import jdk.internal.foreign.abi.Binding.SegmentOffset;
|
||||
import jdk.internal.foreign.abi.Binding.ShiftLeft;
|
||||
import jdk.internal.foreign.abi.Binding.ShiftRight;
|
||||
import jdk.internal.foreign.abi.Binding.UnboxAddress;
|
||||
import jdk.internal.foreign.abi.Binding.VMLoad;
|
||||
import jdk.internal.foreign.abi.Binding.VMStore;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
@ -217,19 +218,19 @@ public class CallingSequenceBuilder {
|
|||
|
||||
static boolean isUnbox(Binding binding) {
|
||||
return switch (binding) {
|
||||
case VMStore unused -> true;
|
||||
case BufferLoad unused -> true;
|
||||
case Copy unused -> true;
|
||||
case UnboxAddress unused -> true;
|
||||
case Dup unused -> true;
|
||||
case ShiftLeft unused -> true;
|
||||
case ShiftRight unused -> true;
|
||||
case Cast unused -> true;
|
||||
|
||||
case VMLoad unused -> false;
|
||||
case BufferStore unused -> false;
|
||||
case Allocate unused -> false;
|
||||
case BoxAddress unused -> false;
|
||||
case VMStore unused -> true;
|
||||
case BufferLoad unused -> true;
|
||||
case Copy unused -> true;
|
||||
case Dup unused -> true;
|
||||
case SegmentBase unused -> true;
|
||||
case SegmentOffset unused -> true;
|
||||
case ShiftLeft unused -> true;
|
||||
case ShiftRight unused -> true;
|
||||
case Cast unused -> true;
|
||||
case VMLoad unused -> false;
|
||||
case BufferStore unused -> false;
|
||||
case Allocate unused -> false;
|
||||
case BoxAddress unused -> false;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -252,19 +253,20 @@ public class CallingSequenceBuilder {
|
|||
|
||||
static boolean isBox(Binding binding) {
|
||||
return switch (binding) {
|
||||
case VMLoad unused -> true;
|
||||
case BufferStore unused -> true;
|
||||
case Copy unused -> true;
|
||||
case Allocate unused -> true;
|
||||
case BoxAddress unused -> true;
|
||||
case Dup unused -> true;
|
||||
case ShiftLeft unused -> true;
|
||||
case ShiftRight unused -> true;
|
||||
case Cast unused -> true;
|
||||
case VMLoad unused -> true;
|
||||
case BufferStore unused -> true;
|
||||
case Copy unused -> true;
|
||||
case Allocate unused -> true;
|
||||
case BoxAddress unused -> true;
|
||||
case Dup unused -> true;
|
||||
case ShiftLeft unused -> true;
|
||||
case ShiftRight unused -> true;
|
||||
case Cast unused -> true;
|
||||
|
||||
case VMStore unused -> false;
|
||||
case BufferLoad unused -> false;
|
||||
case UnboxAddress unused -> false;
|
||||
case VMStore unused -> false;
|
||||
case BufferLoad unused -> false;
|
||||
case SegmentBase unused -> false;
|
||||
case SegmentOffset unused -> false;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -98,9 +98,7 @@ public class DowncallLinker {
|
|||
if (USE_SPEC) {
|
||||
handle = BindingSpecializer.specializeDowncall(handle, callingSequence, abi);
|
||||
} else {
|
||||
Map<VMStorage, Integer> argIndexMap = SharedUtils.indexMap(argMoves);
|
||||
|
||||
InvocationData invData = new InvocationData(handle, callingSequence, argIndexMap);
|
||||
InvocationData invData = new InvocationData(handle, callingSequence);
|
||||
handle = insertArguments(MH_INVOKE_INTERP_BINDINGS.bindTo(this), 2, invData);
|
||||
MethodType interpType = callingSequence.callerMethodType();
|
||||
if (callingSequence.needsReturnBuffer()) {
|
||||
|
@ -151,7 +149,7 @@ public class DowncallLinker {
|
|||
return Arrays.stream(moves).map(Binding.Move::storage).toArray(VMStorage[]::new);
|
||||
}
|
||||
|
||||
private record InvocationData(MethodHandle leaf, CallingSequence callingSequence, Map<VMStorage, Integer> argIndexMap) {}
|
||||
private record InvocationData(MethodHandle leaf, CallingSequence callingSequence) {}
|
||||
|
||||
Object invokeInterpBindings(SegmentAllocator allocator, Object[] args, InvocationData invData) throws Throwable {
|
||||
Arena unboxArena = callingSequence.allocationSize() != 0
|
||||
|
@ -172,6 +170,13 @@ public class DowncallLinker {
|
|||
}
|
||||
|
||||
Object[] leafArgs = new Object[invData.leaf.type().parameterCount()];
|
||||
BindingInterpreter.StoreFunc storeFunc = new BindingInterpreter.StoreFunc() {
|
||||
int argOffset = 0;
|
||||
@Override
|
||||
public void store(VMStorage storage, Object o) {
|
||||
leafArgs[argOffset++] = o;
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
Object arg = args[i];
|
||||
if (callingSequence.functionDesc().argumentLayouts().get(i) instanceof AddressLayout) {
|
||||
|
@ -183,8 +188,7 @@ public class DowncallLinker {
|
|||
acquiredScopes.add(sessionImpl);
|
||||
}
|
||||
}
|
||||
BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i),
|
||||
(storage, value) -> leafArgs[invData.argIndexMap.get(storage)] = value, unboxArena);
|
||||
BindingInterpreter.unbox(arg, callingSequence.argumentBindings(i), storeFunc, unboxArena);
|
||||
}
|
||||
|
||||
// call leaf
|
||||
|
|
|
@ -106,6 +106,11 @@ public class LinkerOptions {
|
|||
return c != null;
|
||||
}
|
||||
|
||||
public boolean allowsHeapAccess() {
|
||||
Critical c = getOption(Critical.class);
|
||||
return c != null && c.allowHeapAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -145,8 +150,9 @@ public class LinkerOptions {
|
|||
}
|
||||
}
|
||||
|
||||
public record Critical() implements LinkerOptionImpl {
|
||||
public static Critical INSTANCE = new Critical();
|
||||
public record Critical(boolean allowHeapAccess) implements LinkerOptionImpl {
|
||||
public static Critical ALLOW_HEAP = new Critical(true);
|
||||
public static Critical DONT_ALLOW_HEAP = new Critical(false);
|
||||
|
||||
@Override
|
||||
public void validateForDowncall(FunctionDescriptor descriptor) {
|
||||
|
|
|
@ -314,10 +314,14 @@ public final class SharedUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static long unboxSegment(MemorySegment segment) {
|
||||
public static void checkNative(MemorySegment segment) {
|
||||
if (!segment.isNative()) {
|
||||
throw new IllegalArgumentException("Heap segment not allowed: " + segment);
|
||||
}
|
||||
}
|
||||
|
||||
public static long unboxSegment(MemorySegment segment) {
|
||||
checkNative(segment);
|
||||
return segment.address();
|
||||
}
|
||||
|
||||
|
|
|
@ -151,8 +151,8 @@ public abstract class CallArranger {
|
|||
|
||||
boolean forVariadicFunction = options.isVariadicFunction();
|
||||
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, forVariadicFunction);
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, forVariadicFunction) : new BoxBindingCalculator(false);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, forVariadicFunction, options.allowsHeapAccess());
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, forVariadicFunction, false) : new BoxBindingCalculator(false);
|
||||
|
||||
boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
|
||||
if (returnInMemory) {
|
||||
|
@ -388,11 +388,13 @@ public abstract class CallArranger {
|
|||
class UnboxBindingCalculator extends BindingCalculator {
|
||||
protected final boolean forArguments;
|
||||
protected final boolean forVariadicFunction;
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments, boolean forVariadicFunction) {
|
||||
UnboxBindingCalculator(boolean forArguments, boolean forVariadicFunction, boolean useAddressPairs) {
|
||||
super(forArguments, forVariadicFunction);
|
||||
this.forArguments = forArguments;
|
||||
this.forVariadicFunction = forVariadicFunction;
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -432,9 +434,17 @@ public abstract class CallArranger {
|
|||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
case POINTER -> {
|
||||
bindings.unboxAddress();
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, (ValueLayout) layout);
|
||||
bindings.vmStore(storage, long.class);
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case INTEGER -> {
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, (ValueLayout) layout);
|
||||
|
|
|
@ -24,13 +24,6 @@
|
|||
*/
|
||||
package jdk.internal.foreign.abi.fallback;
|
||||
|
||||
import jdk.internal.foreign.AbstractMemorySegmentImpl;
|
||||
import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.foreign.abi.AbstractLinker;
|
||||
import jdk.internal.foreign.abi.CapturableState;
|
||||
import jdk.internal.foreign.abi.LinkerOptions;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
|
||||
import java.lang.foreign.AddressLayout;
|
||||
import java.lang.foreign.Arena;
|
||||
import java.lang.foreign.FunctionDescriptor;
|
||||
|
@ -39,16 +32,6 @@ import java.lang.foreign.MemoryLayout;
|
|||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.SegmentAllocator;
|
||||
import java.lang.foreign.ValueLayout;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.ref.Reference;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.lang.foreign.ValueLayout.ADDRESS;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_BOOLEAN;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
|
||||
|
@ -58,7 +41,21 @@ import static java.lang.foreign.ValueLayout.JAVA_FLOAT;
|
|||
import static java.lang.foreign.ValueLayout.JAVA_INT;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_LONG;
|
||||
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import static java.lang.invoke.MethodHandles.foldArguments;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.ref.Reference;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.internal.foreign.AbstractMemorySegmentImpl;
|
||||
import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.foreign.abi.AbstractLinker;
|
||||
import jdk.internal.foreign.abi.CapturableState;
|
||||
import jdk.internal.foreign.abi.LinkerOptions;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
|
||||
public final class FallbackLinker extends AbstractLinker {
|
||||
|
||||
|
@ -95,7 +92,7 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
.mapToInt(CapturableState::mask)
|
||||
.reduce(0, (a, b) -> a | b);
|
||||
DowncallData invData = new DowncallData(cif, function.returnLayout().orElse(null),
|
||||
function.argumentLayouts(), capturedStateMask);
|
||||
function.argumentLayouts(), capturedStateMask, options.allowsHeapAccess());
|
||||
|
||||
MethodHandle target = MethodHandles.insertArguments(MH_DO_DOWNCALL, 2, invData);
|
||||
|
||||
|
@ -155,12 +152,13 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
}
|
||||
|
||||
private record DowncallData(MemorySegment cif, MemoryLayout returnLayout, List<MemoryLayout> argLayouts,
|
||||
int capturedStateMask) {}
|
||||
int capturedStateMask, boolean allowsHeapAccess) {}
|
||||
|
||||
private static Object doDowncall(SegmentAllocator returnAllocator, Object[] args, DowncallData invData) {
|
||||
List<MemorySessionImpl> acquiredSessions = new ArrayList<>();
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
int argStart = 0;
|
||||
Object[] heapBases = invData.allowsHeapAccess() ? new Object[args.length] : null;
|
||||
|
||||
MemorySegment target = (MemorySegment) args[argStart++];
|
||||
MemorySessionImpl targetImpl = ((AbstractMemorySegmentImpl) target).sessionImpl();
|
||||
|
@ -180,12 +178,22 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
for (int i = 0; i < argLayouts.size(); i++) {
|
||||
Object arg = args[argStart + i];
|
||||
MemoryLayout layout = argLayouts.get(i);
|
||||
MemorySegment argSeg = arena.allocate(layout);
|
||||
writeValue(arg, layout, argSeg, addr -> {
|
||||
MemorySessionImpl sessionImpl = ((AbstractMemorySegmentImpl) addr).sessionImpl();
|
||||
|
||||
if (layout instanceof AddressLayout) {
|
||||
AbstractMemorySegmentImpl ms = (AbstractMemorySegmentImpl) arg;
|
||||
MemorySessionImpl sessionImpl = ms.sessionImpl();
|
||||
sessionImpl.acquire0();
|
||||
acquiredSessions.add(sessionImpl);
|
||||
});
|
||||
if (invData.allowsHeapAccess() && !ms.isNative()) {
|
||||
heapBases[i] = ms.unsafeGetBase();
|
||||
// write the offset to the arg segment, add array ptr to it in native code
|
||||
layout = JAVA_LONG;
|
||||
arg = ms.address();
|
||||
}
|
||||
}
|
||||
|
||||
MemorySegment argSeg = arena.allocate(layout);
|
||||
writeValue(arg, layout, argSeg);
|
||||
argPtrs.setAtIndex(ADDRESS, i, argSeg);
|
||||
}
|
||||
|
||||
|
@ -194,7 +202,8 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
retSeg = (invData.returnLayout() instanceof GroupLayout ? returnAllocator : arena).allocate(invData.returnLayout);
|
||||
}
|
||||
|
||||
LibFallback.doDowncall(invData.cif, target, retSeg, argPtrs, capturedState, invData.capturedStateMask());
|
||||
LibFallback.doDowncall(invData.cif, target, retSeg, argPtrs, capturedState, invData.capturedStateMask(),
|
||||
heapBases, args.length);
|
||||
|
||||
Reference.reachabilityFence(invData.cif());
|
||||
|
||||
|
@ -235,11 +244,6 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
|
||||
// where
|
||||
private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg) {
|
||||
writeValue(arg, layout, argSeg, addr -> {});
|
||||
}
|
||||
|
||||
private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg,
|
||||
Consumer<MemorySegment> acquireCallback) {
|
||||
switch (layout) {
|
||||
case ValueLayout.OfBoolean bl -> argSeg.set(bl, 0, (Boolean) arg);
|
||||
case ValueLayout.OfByte bl -> argSeg.set(bl, 0, (Byte) arg);
|
||||
|
@ -249,11 +253,7 @@ public final class FallbackLinker extends AbstractLinker {
|
|||
case ValueLayout.OfLong ll -> argSeg.set(ll, 0, (Long) arg);
|
||||
case ValueLayout.OfFloat fl -> argSeg.set(fl, 0, (Float) arg);
|
||||
case ValueLayout.OfDouble dl -> argSeg.set(dl, 0, (Double) arg);
|
||||
case AddressLayout al -> {
|
||||
MemorySegment addrArg = (MemorySegment) arg;
|
||||
acquireCallback.accept(addrArg);
|
||||
argSeg.set(al, 0, addrArg);
|
||||
}
|
||||
case AddressLayout al -> argSeg.set(al, 0, (MemorySegment) arg);
|
||||
case GroupLayout _ ->
|
||||
MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct
|
||||
case null, default -> {
|
||||
|
|
|
@ -93,10 +93,12 @@ final class LibFallback {
|
|||
* @see jdk.internal.foreign.abi.CapturableState
|
||||
*/
|
||||
static void doDowncall(MemorySegment cif, MemorySegment target, MemorySegment retPtr, MemorySegment argPtrs,
|
||||
MemorySegment capturedState, int capturedStateMask) {
|
||||
MemorySegment capturedState, int capturedStateMask,
|
||||
Object[] heapBases, int numArgs) {
|
||||
doDowncall(cif.address(), target.address(),
|
||||
retPtr == null ? 0 : retPtr.address(), argPtrs.address(),
|
||||
capturedState == null ? 0 : capturedState.address(), capturedStateMask);
|
||||
retPtr == null ? 0 : retPtr.address(), argPtrs.address(),
|
||||
capturedState == null ? 0 : capturedState.address(), capturedStateMask,
|
||||
heapBases, numArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +212,9 @@ final class LibFallback {
|
|||
|
||||
private static native int createClosure(long cif, Object userData, long[] ptrs);
|
||||
private static native void freeClosure(long closureAddress, long globalTarget);
|
||||
private static native void doDowncall(long cif, long fn, long rvalue, long avalues, long capturedState, int capturedStateMask);
|
||||
private static native void doDowncall(long cif, long fn, long rvalue, long avalues,
|
||||
long capturedState, int capturedStateMask,
|
||||
Object[] heapBases, int numArgs);
|
||||
|
||||
private static native int ffi_prep_cif(long cif, int abi, int nargs, long rtype, long atypes);
|
||||
private static native int ffi_prep_cif_var(long cif, int abi, int nfixedargs, int ntotalargs, long rtype, long atypes);
|
||||
|
|
|
@ -110,8 +110,8 @@ public abstract class CallArranger {
|
|||
public Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) {
|
||||
CallingSequenceBuilder csb = new CallingSequenceBuilder(C, forUpcall, options);
|
||||
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess());
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false);
|
||||
|
||||
boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
|
||||
if (returnInMemory) {
|
||||
|
@ -343,8 +343,11 @@ public abstract class CallArranger {
|
|||
|
||||
// Compute recipe for transfering arguments / return values to C from Java.
|
||||
class UnboxBindingCalculator extends BindingCalculator {
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) {
|
||||
super(forArguments);
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -411,8 +414,16 @@ public abstract class CallArranger {
|
|||
}
|
||||
case POINTER -> {
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER, false);
|
||||
bindings.unboxAddress()
|
||||
.vmStore(storage, long.class);
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case INTEGER -> {
|
||||
// ABI requires all int types to get extended to 64 bit.
|
||||
|
|
|
@ -85,8 +85,8 @@ public class LinuxRISCV64CallArranger {
|
|||
|
||||
public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) {
|
||||
CallingSequenceBuilder csb = new CallingSequenceBuilder(CLinux, forUpcall, options);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess());
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false);
|
||||
|
||||
boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
|
||||
if (returnInMemory) {
|
||||
|
@ -252,11 +252,13 @@ public class LinuxRISCV64CallArranger {
|
|||
}
|
||||
|
||||
static final class UnboxBindingCalculator extends BindingCalculator {
|
||||
final boolean forArguments;
|
||||
protected final boolean forArguments;
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) {
|
||||
super(forArguments);
|
||||
this.forArguments = forArguments;
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,9 +282,17 @@ public class LinuxRISCV64CallArranger {
|
|||
bindings.vmStore(storage, carrier);
|
||||
}
|
||||
case POINTER -> {
|
||||
bindings.unboxAddress();
|
||||
VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER);
|
||||
bindings.vmStore(storage, long.class);
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case STRUCT_REGISTER_X -> {
|
||||
assert carrier == MemorySegment.class;
|
||||
|
|
|
@ -82,8 +82,8 @@ public class LinuxS390CallArranger {
|
|||
public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) {
|
||||
CallingSequenceBuilder csb = new CallingSequenceBuilder(CLinux, forUpcall, options);
|
||||
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess());
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false);
|
||||
|
||||
boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
|
||||
if (returnInMemory) {
|
||||
|
@ -199,8 +199,11 @@ public class LinuxS390CallArranger {
|
|||
|
||||
// Compute recipe for transferring arguments / return values to C from Java.
|
||||
static class UnboxBindingCalculator extends BindingCalculator {
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) {
|
||||
super(forArguments);
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -231,8 +234,16 @@ public class LinuxS390CallArranger {
|
|||
}
|
||||
case POINTER -> {
|
||||
VMStorage storage = storageCalculator.getStorage(StorageType.INTEGER, false);
|
||||
bindings.unboxAddress()
|
||||
.vmStore(storage, long.class);
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case INTEGER -> {
|
||||
// ABI requires all int types to get extended to 64 bit.
|
||||
|
|
|
@ -97,8 +97,8 @@ public class CallArranger {
|
|||
public static Bindings getBindings(MethodType mt, FunctionDescriptor cDesc, boolean forUpcall, LinkerOptions options) {
|
||||
CallingSequenceBuilder csb = new CallingSequenceBuilder(CSysV, forUpcall, options);
|
||||
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
|
||||
BindingCalculator argCalc = forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess());
|
||||
BindingCalculator retCalc = forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false);
|
||||
|
||||
boolean returnInMemory = isInMemoryReturn(cDesc.returnLayout());
|
||||
if (returnInMemory) {
|
||||
|
@ -246,9 +246,11 @@ public class CallArranger {
|
|||
}
|
||||
|
||||
static class UnboxBindingCalculator extends BindingCalculator {
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) {
|
||||
super(forArguments);
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -275,10 +277,18 @@ public class CallArranger {
|
|||
}
|
||||
}
|
||||
case POINTER -> {
|
||||
bindings.unboxAddress();
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER);
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case INTEGER -> {
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER);
|
||||
bindings.vmStore(storage, carrier);
|
||||
|
|
|
@ -87,9 +87,9 @@ public class CallArranger {
|
|||
class CallingSequenceBuilderHelper {
|
||||
final CallingSequenceBuilder csb = new CallingSequenceBuilder(CWindows, forUpcall, options);
|
||||
final BindingCalculator argCalc =
|
||||
forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true);
|
||||
forUpcall ? new BoxBindingCalculator(true) : new UnboxBindingCalculator(true, options.allowsHeapAccess());
|
||||
final BindingCalculator retCalc =
|
||||
forUpcall ? new UnboxBindingCalculator(false) : new BoxBindingCalculator(false);
|
||||
forUpcall ? new UnboxBindingCalculator(false, false) : new BoxBindingCalculator(false);
|
||||
|
||||
void addArgumentBindings(Class<?> carrier, MemoryLayout layout, boolean isVararg) {
|
||||
csb.addArgumentBindings(carrier, layout, argCalc.getBindings(carrier, layout, isVararg));
|
||||
|
@ -184,9 +184,12 @@ public class CallArranger {
|
|||
|
||||
static class UnboxBindingCalculator implements BindingCalculator {
|
||||
private final StorageCalculator storageCalculator;
|
||||
private final boolean useAddressPairs;
|
||||
|
||||
UnboxBindingCalculator(boolean forArguments) {
|
||||
UnboxBindingCalculator(boolean forArguments, boolean useAddressPairs) {
|
||||
this.storageCalculator = new StorageCalculator(forArguments);
|
||||
assert !useAddressPairs || forArguments;
|
||||
this.useAddressPairs = useAddressPairs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -209,9 +212,17 @@ public class CallArranger {
|
|||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
case POINTER -> {
|
||||
bindings.unboxAddress();
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER);
|
||||
bindings.vmStore(storage, long.class);
|
||||
if (useAddressPairs) {
|
||||
bindings.dup()
|
||||
.segmentBase()
|
||||
.vmStore(storage, Object.class)
|
||||
.segmentOffsetAllowHeap()
|
||||
.vmStore(null, long.class);
|
||||
} else {
|
||||
bindings.unboxAddress();
|
||||
bindings.vmStore(storage, long.class);
|
||||
}
|
||||
}
|
||||
case INTEGER -> {
|
||||
VMStorage storage = storageCalculator.nextStorage(StorageType.INTEGER);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue