Skip to content

Commit

Permalink
8302346: Lift upcall sharing mechanism to AbstractLinker
Browse files Browse the repository at this point in the history
Reviewed-by: mcimadamore
  • Loading branch information
JornVernee committed Feb 19, 2023
1 parent 1dfb729 commit 9664ae3
Show file tree
Hide file tree
Showing 16 changed files with 115 additions and 116 deletions.
Expand Up @@ -50,9 +50,13 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
Windowsx64Linker, LinuxRISCV64Linker,
FallbackLinker {

public interface UpcallStubFactory {
MemorySegment makeStub(MethodHandle target, Arena arena);
}

private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {}
private final SoftReferenceCache<LinkRequest, MethodHandle> DOWNCALL_CACHE = new SoftReferenceCache<>();
private final SoftReferenceCache<LinkRequest, UpcallStubFactory> UPCALL_CACHE = new SoftReferenceCache<>();

@Override
public MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
Expand Down Expand Up @@ -84,12 +88,13 @@ public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function
if (!type.equals(target.type())) {
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
}
return arrangeUpcall(target, target.type(), function, arena, optionSet);

UpcallStubFactory factory = UPCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest ->
arrangeUpcall(type, linkRequest.descriptor(), linkRequest.options()));
return factory.makeStub(target, arena);
}

protected abstract MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType,
FunctionDescriptor function, Arena arena,
LinkerOptions options);
protected abstract UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options);

@Override
public SystemLookup defaultLookup() {
Expand Down
Expand Up @@ -107,8 +107,6 @@ public class BindingSpecializer {

private static final String SUPER_NAME = OBJECT_INTRN;

private static final SoftReferenceCache<FunctionDescriptor, MethodHandle> UPCALL_WRAPPER_CACHE = new SoftReferenceCache<>();

// Instance fields start here
private final MethodVisitor mv;
private final MethodType callerMethodType;
Expand Down Expand Up @@ -138,16 +136,7 @@ private BindingSpecializer(MethodVisitor mv, MethodType callerMethodType, Callin
this.leafType = leafType;
}

static MethodHandle specialize(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
if (callingSequence.forUpcall()) {
MethodHandle wrapper = UPCALL_WRAPPER_CACHE.get(callingSequence.functionDesc(), fd -> specializeUpcall(leafHandle, callingSequence, abi));
return MethodHandles.insertArguments(wrapper, 0, leafHandle); // lazily customized for leaf handle instances
} else {
return specializeDowncall(leafHandle, callingSequence, abi);
}
}

private static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
MethodType callerMethodType = callingSequence.callerMethodType();
if (callingSequence.needsReturnBuffer()) {
callerMethodType = callerMethodType.dropParameterTypes(0, 1); // Return buffer does not appear in the parameter list
Expand All @@ -165,11 +154,11 @@ private static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingS
}
}

private static MethodHandle specializeUpcall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
static MethodHandle specializeUpcall(MethodType targetType, CallingSequence callingSequence, ABIDescriptor abi) {
MethodType callerMethodType = callingSequence.callerMethodType();
callerMethodType = callerMethodType.insertParameterTypes(0, MethodHandle.class); // target

byte[] bytes = specializeHelper(leafHandle.type(), callerMethodType, callingSequence, abi);
byte[] bytes = specializeHelper(targetType, callerMethodType, callingSequence, abi);

try {
// For upcalls, we must initialize the class since the upcall stubs don't have a clinit barrier,
Expand Down
Expand Up @@ -89,7 +89,7 @@ public MethodHandle getBoundMethodHandle() {
MethodHandle handle = JLIA.nativeMethodHandle(nep);

if (USE_SPEC) {
handle = BindingSpecializer.specialize(handle, callingSequence, abi);
handle = BindingSpecializer.specializeDowncall(handle, callingSequence, abi);
} else {
Map<VMStorage, Integer> argIndexMap = SharedUtils.indexMap(argMoves);
Map<VMStorage, Integer> retIndexMap = SharedUtils.indexMap(retMoves);
Expand Down Expand Up @@ -196,4 +196,3 @@ public Object load(VMStorage storage, Class<?> type) {
}
}
}

Expand Up @@ -28,6 +28,7 @@
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.CABI;
import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
Expand Down Expand Up @@ -140,7 +141,7 @@ public static MethodHandle adaptDowncallForIMR(MethodHandle handle, FunctionDesc
* @param target the target handle to adapt
* @return the adapted handle
*/
public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
private static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
if (target.type().returnType() != MemorySegment.class)
throw new IllegalArgumentException("Must return MemorySegment for IMR");

Expand All @@ -157,6 +158,27 @@ public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropRe
return target;
}

public static UpcallStubFactory arrangeUpcallHelper(MethodType targetType, boolean isInMemoryReturn, boolean dropReturn,
ABIDescriptor abi, CallingSequence callingSequence) {
if (isInMemoryReturn) {
// simulate the adaptation to get the type
MethodHandle fakeTarget = MethodHandles.empty(targetType);
targetType = adaptUpcallForIMR(fakeTarget, dropReturn).type();
}

UpcallStubFactory factory = UpcallLinker.makeFactory(targetType, abi, callingSequence);

if (isInMemoryReturn) {
final UpcallStubFactory finalFactory = factory;
factory = (target, scope) -> {
target = adaptUpcallForIMR(target, dropReturn);
return finalFactory.makeStub(target, scope);
};
}

return factory;
}

private static MemorySegment bufferCopy(MemorySegment dest, MemorySegment buffer) {
return dest.copyFrom(buffer);
}
Expand Down
Expand Up @@ -25,16 +25,17 @@

package jdk.internal.foreign.abi;

import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
import sun.security.action.GetPropertyAction;

import java.lang.foreign.MemorySegment;
import java.lang.foreign.Arena;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;

import static java.lang.invoke.MethodHandles.exactInvoker;
Expand All @@ -55,45 +56,57 @@ public class UpcallLinker {
try {
MethodHandles.Lookup lookup = lookup();
MH_invokeInterpBindings = lookup.findStatic(UpcallLinker.class, "invokeInterpBindings",
methodType(Object.class, Object[].class, InvocationData.class));
methodType(Object.class, MethodHandle.class, Object[].class, InvocationData.class));
} catch (ReflectiveOperationException e) {
throw new InternalError(e);
}
}

public static MemorySegment make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence, Arena scope) {
public static UpcallStubFactory makeFactory(MethodType targetType, ABIDescriptor abi, CallingSequence callingSequence) {
assert callingSequence.forUpcall();
Binding.VMLoad[] argMoves = argMoveBindings(callingSequence);
Binding.VMStore[] retMoves = retMoveBindings(callingSequence);

MethodType llType = callingSequence.callerMethodType();

MethodHandle doBindings;
UnaryOperator<MethodHandle> doBindingsMaker;
if (USE_SPEC) {
doBindings = BindingSpecializer.specialize(target, callingSequence, abi);
assert doBindings.type() == llType;
MethodHandle doBindings = BindingSpecializer.specializeUpcall(targetType, callingSequence, abi);
doBindingsMaker = target -> {
MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target);
assert handle.type() == llType;
return handle;
};
} else {
Map<VMStorage, Integer> argIndices = SharedUtils.indexMap(argMoves);
Map<VMStorage, Integer> retIndices = SharedUtils.indexMap(retMoves);
int spreaderCount = callingSequence.calleeMethodType().parameterCount();
if (callingSequence.needsReturnBuffer()) {
spreaderCount--; // return buffer is dropped from the argument list
}
target = target.asSpreader(Object[].class, spreaderCount);
InvocationData invData = new InvocationData(target, argIndices, retIndices, callingSequence, retMoves, abi);
doBindings = insertArguments(MH_invokeInterpBindings, 1, invData);
doBindings = doBindings.asCollector(Object[].class, llType.parameterCount());
doBindings = doBindings.asType(llType);
final int finalSpreaderCount = spreaderCount;
InvocationData invData = new InvocationData(argIndices, retIndices, callingSequence, retMoves, abi);
MethodHandle doBindings = insertArguments(MH_invokeInterpBindings, 2, invData);
doBindingsMaker = target -> {
target = target.asSpreader(Object[].class, finalSpreaderCount);
MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target);
handle = handle.asCollector(Object[].class, llType.parameterCount());
return handle.asType(llType);
};
}

checkPrimitive(doBindings.type());
doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings);
VMStorage[] args = Arrays.stream(argMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
VMStorage[] rets = Arrays.stream(retMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
CallRegs conv = new CallRegs(args, rets);
long entryPoint = makeUpcallStub(doBindings, abi, conv,
callingSequence.needsReturnBuffer(), callingSequence.returnBufferSize());
return UpcallStubs.makeUpcall(entryPoint, scope);
return (target, scope) -> {
assert target.type() == targetType;
MethodHandle doBindings = doBindingsMaker.apply(target);
checkPrimitive(doBindings.type());
doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings);
long entryPoint = makeUpcallStub(doBindings, abi, conv,
callingSequence.needsReturnBuffer(), callingSequence.returnBufferSize());
return UpcallStubs.makeUpcall(entryPoint, scope);
};
}

private static void checkPrimitive(MethodType type) {
Expand All @@ -120,14 +133,13 @@ private static Binding.VMStore[] retMoveBindings(CallingSequence callingSequence
.toArray(Binding.VMStore[]::new);
}

private record InvocationData(MethodHandle leaf,
Map<VMStorage, Integer> argIndexMap,
private record InvocationData(Map<VMStorage, Integer> argIndexMap,
Map<VMStorage, Integer> retIndexMap,
CallingSequence callingSequence,
Binding.VMStore[] retMoves,
ABIDescriptor abi) {}

private static Object invokeInterpBindings(Object[] lowLevelArgs, InvocationData invData) throws Throwable {
private static Object invokeInterpBindings(MethodHandle leaf, Object[] lowLevelArgs, InvocationData invData) throws Throwable {
Binding.Context allocator = invData.callingSequence.allocationSize() != 0
? Binding.Context.ofBoundedAllocator(invData.callingSequence.allocationSize())
: Binding.Context.ofScope();
Expand All @@ -154,15 +166,15 @@ private static Object invokeInterpBindings(Object[] lowLevelArgs, InvocationData
}

// invoke our target
Object o = invData.leaf.invoke(highLevelArgs);
Object o = leaf.invoke(highLevelArgs);

if (DEBUG) {
System.err.println("Java return:");
System.err.println(Objects.toString(o).indent(2));
}

Object[] returnValues = new Object[invData.retIndexMap.size()];
if (invData.leaf.type().returnType() != void.class) {
if (leaf.type().returnType() != void.class) {
BindingInterpreter.unbox(o, invData.callingSequence.returnBindings(),
(storage, type, value) -> returnValues[invData.retIndexMap.get(storage)] = value, null);
}
Expand Down
Expand Up @@ -25,12 +25,12 @@
*/
package jdk.internal.foreign.abi.aarch64;

import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import jdk.internal.foreign.abi.ABIDescriptor;
import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
import jdk.internal.foreign.abi.Binding;
import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
Expand Down Expand Up @@ -188,14 +188,12 @@ public MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, Lin
return handle;
}

public MemorySegment arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, Arena session, LinkerOptions options) {
public UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc,
LinkerOptions options) {
Bindings bindings = getBindings(mt, cDesc, true, options);

if (bindings.isInMemoryReturn) {
target = SharedUtils.adaptUpcallForIMR(target, true /* drop return, since we don't have bindings for it */);
}

return UpcallLinker.make(abiDescriptor(), target, bindings.callingSequence, session);
final boolean dropReturn = true; /* drop return, since we don't have bindings for it */
return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, abiDescriptor(),
bindings.callingSequence);
}

private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
Expand Down
Expand Up @@ -29,12 +29,9 @@
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.aarch64.CallArranger;

import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.function.Consumer;

/**
* ABI implementation based on ARM document "Procedure Call Standard for
Expand All @@ -60,7 +57,7 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
}

@Override
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, Arena scope, LinkerOptions options) {
return CallArranger.LINUX.arrangeUpcall(target, targetType, function, scope, options);
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.LINUX.arrangeUpcall(targetType, function, options);
}
}
Expand Up @@ -29,12 +29,9 @@
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.aarch64.CallArranger;

import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.function.Consumer;

/**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with
Expand All @@ -60,7 +57,7 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
}

@Override
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, Arena scope, LinkerOptions options) {
return CallArranger.MACOS.arrangeUpcall(target, targetType, function, scope, options);
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.MACOS.arrangeUpcall(targetType, function, options);
}
}
Expand Up @@ -30,12 +30,9 @@
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.aarch64.CallArranger;

import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.function.Consumer;

/**
* ABI implementation for Windows/AArch64. Based on AAPCS with
Expand All @@ -57,8 +54,8 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
}

@Override
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, Arena scope, LinkerOptions options) {
return CallArranger.WINDOWS.arrangeUpcall(target, targetType, function, scope, options);
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function, LinkerOptions options) {
return CallArranger.WINDOWS.arrangeUpcall(targetType, function, options);
}

}

0 comments on commit 9664ae3

Please sign in to comment.