Skip to content

Commit d4eb395

Browse files
committed
8303684: Lift upcall sharing mechanism to AbstractLinker (mainline)
Reviewed-by: mcimadamore
1 parent dfc7214 commit d4eb395

16 files changed

+120
-100
lines changed

src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -45,10 +45,16 @@
4545
import java.util.Objects;
4646

4747
public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
48-
SysVx64Linker, WindowsAArch64Linker, Windowsx64Linker, LinuxRISCV64Linker {
48+
SysVx64Linker, WindowsAArch64Linker,
49+
Windowsx64Linker, LinuxRISCV64Linker {
50+
51+
public interface UpcallStubFactory {
52+
MemorySegment makeStub(MethodHandle target, SegmentScope arena);
53+
}
4954

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

5359
@Override
5460
public MethodHandle downcallHandle(FunctionDescriptor function, Option... options) {
@@ -79,11 +85,12 @@ public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function
7985
if (!type.equals(target.type())) {
8086
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
8187
}
82-
return arrangeUpcall(target, target.type(), function, scope);
88+
89+
UpcallStubFactory factory = UPCALL_CACHE.get(function, f -> arrangeUpcall(type, f));
90+
return factory.makeStub(target, scope);
8391
}
8492

85-
protected abstract MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType,
86-
FunctionDescriptor function, SegmentScope scope);
93+
protected abstract UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function);
8794

8895
@Override
8996
public SystemLookup defaultLookup() {

src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -126,8 +126,6 @@ public class BindingSpecializer {
126126

127127
private static final String SUPER_NAME = OBJECT_INTRN;
128128

129-
private static final SoftReferenceCache<FunctionDescriptor, MethodHandle> UPCALL_WRAPPER_CACHE = new SoftReferenceCache<>();
130-
131129
// Instance fields start here
132130
private final MethodVisitor mv;
133131
private final MethodType callerMethodType;
@@ -157,16 +155,7 @@ private BindingSpecializer(MethodVisitor mv, MethodType callerMethodType, Callin
157155
this.leafType = leafType;
158156
}
159157

160-
static MethodHandle specialize(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
161-
if (callingSequence.forUpcall()) {
162-
MethodHandle wrapper = UPCALL_WRAPPER_CACHE.get(callingSequence.functionDesc(), fd -> specializeUpcall(leafHandle, callingSequence, abi));
163-
return MethodHandles.insertArguments(wrapper, 0, leafHandle); // lazily customized for leaf handle instances
164-
} else {
165-
return specializeDowncall(leafHandle, callingSequence, abi);
166-
}
167-
}
168-
169-
private static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
158+
static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
170159
MethodType callerMethodType = callingSequence.callerMethodType();
171160
if (callingSequence.needsReturnBuffer()) {
172161
callerMethodType = callerMethodType.dropParameterTypes(0, 1); // Return buffer does not appear in the parameter list
@@ -183,11 +172,11 @@ private static MethodHandle specializeDowncall(MethodHandle leafHandle, CallingS
183172
}
184173
}
185174

186-
private static MethodHandle specializeUpcall(MethodHandle leafHandle, CallingSequence callingSequence, ABIDescriptor abi) {
175+
static MethodHandle specializeUpcall(MethodType targetType, CallingSequence callingSequence, ABIDescriptor abi) {
187176
MethodType callerMethodType = callingSequence.callerMethodType();
188177
callerMethodType = callerMethodType.insertParameterTypes(0, MethodHandle.class); // target
189178

190-
byte[] bytes = specializeHelper(leafHandle.type(), callerMethodType, callingSequence, abi);
179+
byte[] bytes = specializeHelper(targetType, callerMethodType, callingSequence, abi);
191180

192181
try {
193182
// For upcalls, we must initialize the class since the upcall stubs don't have a clinit barrier,

src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -91,7 +91,7 @@ public MethodHandle getBoundMethodHandle() {
9191
MethodHandle handle = JLIA.nativeMethodHandle(nep);
9292

9393
if (USE_SPEC) {
94-
handle = BindingSpecializer.specialize(handle, callingSequence, abi);
94+
handle = BindingSpecializer.specializeDowncall(handle, callingSequence, abi);
9595
} else {
9696
Map<VMStorage, Integer> argIndexMap = SharedUtils.indexMap(argMoves);
9797
Map<VMStorage, Integer> retIndexMap = SharedUtils.indexMap(retMoves);
@@ -198,4 +198,3 @@ public Object load(VMStorage storage, Class<?> type) {
198198
}
199199
}
200200
}
201-

src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import jdk.internal.access.JavaLangInvokeAccess;
2929
import jdk.internal.access.SharedSecrets;
3030
import jdk.internal.foreign.CABI;
31+
import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
3132
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
3233
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
3334
import jdk.internal.foreign.abi.aarch64.windows.WindowsAArch64Linker;
@@ -137,7 +138,7 @@ public static MethodHandle adaptDowncallForIMR(MethodHandle handle, FunctionDesc
137138
* @param target the target handle to adapt
138139
* @return the adapted handle
139140
*/
140-
public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
141+
private static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropReturn) {
141142
if (target.type().returnType() != MemorySegment.class)
142143
throw new IllegalArgumentException("Must return MemorySegment for IMR");
143144

@@ -154,6 +155,27 @@ public static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropRe
154155
return target;
155156
}
156157

158+
public static UpcallStubFactory arrangeUpcallHelper(MethodType targetType, boolean isInMemoryReturn, boolean dropReturn,
159+
ABIDescriptor abi, CallingSequence callingSequence) {
160+
if (isInMemoryReturn) {
161+
// simulate the adaptation to get the type
162+
MethodHandle fakeTarget = MethodHandles.empty(targetType);
163+
targetType = adaptUpcallForIMR(fakeTarget, dropReturn).type();
164+
}
165+
166+
UpcallStubFactory factory = UpcallLinker.makeFactory(targetType, abi, callingSequence);
167+
168+
if (isInMemoryReturn) {
169+
final UpcallStubFactory finalFactory = factory;
170+
factory = (target, scope) -> {
171+
target = adaptUpcallForIMR(target, dropReturn);
172+
return finalFactory.makeStub(target, scope);
173+
};
174+
}
175+
176+
return factory;
177+
}
178+
157179
private static MemorySegment bufferCopy(MemorySegment dest, MemorySegment buffer) {
158180
return dest.copyFrom(buffer);
159181
}

src/java.base/share/classes/jdk/internal/foreign/abi/UpcallLinker.java

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
2525

2626
package jdk.internal.foreign.abi;
2727

28+
import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
2829
import sun.security.action.GetPropertyAction;
2930

3031
import java.lang.foreign.MemorySegment;
@@ -35,6 +36,7 @@
3536
import java.util.Arrays;
3637
import java.util.Map;
3738
import java.util.Objects;
39+
import java.util.function.UnaryOperator;
3840
import java.util.stream.Stream;
3941

4042
import static java.lang.invoke.MethodHandles.exactInvoker;
@@ -55,45 +57,57 @@ public class UpcallLinker {
5557
try {
5658
MethodHandles.Lookup lookup = lookup();
5759
MH_invokeInterpBindings = lookup.findStatic(UpcallLinker.class, "invokeInterpBindings",
58-
methodType(Object.class, Object[].class, InvocationData.class));
60+
methodType(Object.class, MethodHandle.class, Object[].class, InvocationData.class));
5961
} catch (ReflectiveOperationException e) {
6062
throw new InternalError(e);
6163
}
6264
}
6365

64-
public static MemorySegment make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence, SegmentScope scope) {
66+
public static UpcallStubFactory makeFactory(MethodType targetType, ABIDescriptor abi, CallingSequence callingSequence) {
6567
assert callingSequence.forUpcall();
6668
Binding.VMLoad[] argMoves = argMoveBindings(callingSequence);
6769
Binding.VMStore[] retMoves = retMoveBindings(callingSequence);
6870

6971
MethodType llType = callingSequence.callerMethodType();
7072

71-
MethodHandle doBindings;
73+
UnaryOperator<MethodHandle> doBindingsMaker;
7274
if (USE_SPEC) {
73-
doBindings = BindingSpecializer.specialize(target, callingSequence, abi);
74-
assert doBindings.type() == llType;
75+
MethodHandle doBindings = BindingSpecializer.specializeUpcall(targetType, callingSequence, abi);
76+
doBindingsMaker = target -> {
77+
MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target);
78+
assert handle.type() == llType;
79+
return handle;
80+
};
7581
} else {
7682
Map<VMStorage, Integer> argIndices = SharedUtils.indexMap(argMoves);
7783
Map<VMStorage, Integer> retIndices = SharedUtils.indexMap(retMoves);
7884
int spreaderCount = callingSequence.calleeMethodType().parameterCount();
7985
if (callingSequence.needsReturnBuffer()) {
8086
spreaderCount--; // return buffer is dropped from the argument list
8187
}
82-
target = target.asSpreader(Object[].class, spreaderCount);
83-
InvocationData invData = new InvocationData(target, argIndices, retIndices, callingSequence, retMoves, abi);
84-
doBindings = insertArguments(MH_invokeInterpBindings, 1, invData);
85-
doBindings = doBindings.asCollector(Object[].class, llType.parameterCount());
86-
doBindings = doBindings.asType(llType);
88+
final int finalSpreaderCount = spreaderCount;
89+
InvocationData invData = new InvocationData(argIndices, retIndices, callingSequence, retMoves, abi);
90+
MethodHandle doBindings = insertArguments(MH_invokeInterpBindings, 2, invData);
91+
doBindingsMaker = target -> {
92+
target = target.asSpreader(Object[].class, finalSpreaderCount);
93+
MethodHandle handle = MethodHandles.insertArguments(doBindings, 0, target);
94+
handle = handle.asCollector(Object[].class, llType.parameterCount());
95+
return handle.asType(llType);
96+
};
8797
}
8898

89-
checkPrimitive(doBindings.type());
90-
doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings);
9199
VMStorage[] args = Arrays.stream(argMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
92100
VMStorage[] rets = Arrays.stream(retMoves).map(Binding.Move::storage).toArray(VMStorage[]::new);
93101
CallRegs conv = new CallRegs(args, rets);
94-
long entryPoint = makeUpcallStub(doBindings, abi, conv,
95-
callingSequence.needsReturnBuffer(), callingSequence.returnBufferSize());
96-
return UpcallStubs.makeUpcall(entryPoint, scope);
102+
return (target, scope) -> {
103+
assert target.type() == targetType;
104+
MethodHandle doBindings = doBindingsMaker.apply(target);
105+
checkPrimitive(doBindings.type());
106+
doBindings = insertArguments(exactInvoker(doBindings.type()), 0, doBindings);
107+
long entryPoint = makeUpcallStub(doBindings, abi, conv,
108+
callingSequence.needsReturnBuffer(), callingSequence.returnBufferSize());
109+
return UpcallStubs.makeUpcall(entryPoint, scope);
110+
};
97111
}
98112

99113
private static void checkPrimitive(MethodType type) {
@@ -120,14 +134,13 @@ private static Binding.VMStore[] retMoveBindings(CallingSequence callingSequence
120134
.toArray(Binding.VMStore[]::new);
121135
}
122136

123-
private record InvocationData(MethodHandle leaf,
124-
Map<VMStorage, Integer> argIndexMap,
137+
private record InvocationData(Map<VMStorage, Integer> argIndexMap,
125138
Map<VMStorage, Integer> retIndexMap,
126139
CallingSequence callingSequence,
127140
Binding.VMStore[] retMoves,
128141
ABIDescriptor abi) {}
129142

130-
private static Object invokeInterpBindings(Object[] lowLevelArgs, InvocationData invData) throws Throwable {
143+
private static Object invokeInterpBindings(MethodHandle leaf, Object[] lowLevelArgs, InvocationData invData) throws Throwable {
131144
Binding.Context allocator = invData.callingSequence.allocationSize() != 0
132145
? Binding.Context.ofBoundedAllocator(invData.callingSequence.allocationSize())
133146
: Binding.Context.ofScope();
@@ -154,15 +167,15 @@ private static Object invokeInterpBindings(Object[] lowLevelArgs, InvocationData
154167
}
155168

156169
// invoke our target
157-
Object o = invData.leaf.invoke(highLevelArgs);
170+
Object o = leaf.invoke(highLevelArgs);
158171

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

164177
Object[] returnValues = new Object[invData.retIndexMap.size()];
165-
if (invData.leaf.type().returnType() != void.class) {
178+
if (leaf.type().returnType() != void.class) {
166179
BindingInterpreter.unbox(o, invData.callingSequence.returnBindings(),
167180
(storage, type, value) -> returnValues[invData.retIndexMap.get(storage)] = value, null);
168181
}

src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.lang.foreign.MemoryLayout;
3131
import java.lang.foreign.MemorySegment;
3232
import jdk.internal.foreign.abi.ABIDescriptor;
33+
import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory;
3334
import jdk.internal.foreign.abi.Binding;
3435
import jdk.internal.foreign.abi.CallingSequence;
3536
import jdk.internal.foreign.abi.CallingSequenceBuilder;
@@ -189,14 +190,11 @@ public MethodHandle arrangeDowncall(MethodType mt, FunctionDescriptor cDesc, Lin
189190
return handle;
190191
}
191192

192-
public MemorySegment arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, SegmentScope session) {
193+
public UpcallStubFactory arrangeUpcall(MethodType mt, FunctionDescriptor cDesc) {
193194
Bindings bindings = getBindings(mt, cDesc, true);
194-
195-
if (bindings.isInMemoryReturn) {
196-
target = SharedUtils.adaptUpcallForIMR(target, true /* drop return, since we don't have bindings for it */);
197-
}
198-
199-
return UpcallLinker.make(abiDescriptor(), target, bindings.callingSequence, session);
195+
final boolean dropReturn = true; /* drop return, since we don't have bindings for it */
196+
return SharedUtils.arrangeUpcallHelper(mt, bindings.isInMemoryReturn, dropReturn, abiDescriptor(),
197+
bindings.callingSequence);
200198
}
201199

202200
private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {

src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/linux/LinuxAArch64Linker.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2019, 2021, Arm Limited. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -31,7 +31,6 @@
3131

3232
import java.lang.foreign.SegmentScope;
3333
import java.lang.foreign.FunctionDescriptor;
34-
import java.lang.foreign.MemorySegment;
3534
import java.lang.foreign.VaList;
3635
import java.lang.invoke.MethodHandle;
3736
import java.lang.invoke.MethodType;
@@ -61,8 +60,8 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
6160
}
6261

6362
@Override
64-
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, SegmentScope scope) {
65-
return CallArranger.LINUX.arrangeUpcall(target, targetType, function, scope);
63+
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function) {
64+
return CallArranger.LINUX.arrangeUpcall(targetType, function);
6665
}
6766

6867
public static VaList newVaList(Consumer<VaList.Builder> actions, SegmentScope scope) {

src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2021, Arm Limited. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -30,7 +30,6 @@
3030
import jdk.internal.foreign.abi.aarch64.CallArranger;
3131

3232
import java.lang.foreign.FunctionDescriptor;
33-
import java.lang.foreign.MemorySegment;
3433
import java.lang.foreign.SegmentScope;
3534
import java.lang.foreign.VaList;
3635
import java.lang.invoke.MethodHandle;
@@ -61,8 +60,8 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
6160
}
6261

6362
@Override
64-
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, SegmentScope scope) {
65-
return CallArranger.MACOS.arrangeUpcall(target, targetType, function, scope);
63+
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function) {
64+
return CallArranger.MACOS.arrangeUpcall(targetType, function);
6665
}
6766

6867
public static VaList newVaList(Consumer<VaList.Builder> actions, SegmentScope scope) {

src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
33
* Copyright (c) 2021, Arm Limited. All rights reserved.
44
* Copyright (c) 2021, 2022, Microsoft. All rights reserved.
55
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -31,7 +31,6 @@
3131
import jdk.internal.foreign.abi.aarch64.CallArranger;
3232

3333
import java.lang.foreign.FunctionDescriptor;
34-
import java.lang.foreign.MemorySegment;
3534
import java.lang.foreign.SegmentScope;
3635
import java.lang.foreign.VaList;
3736
import java.lang.invoke.MethodHandle;
@@ -58,8 +57,8 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe
5857
}
5958

6059
@Override
61-
protected MemorySegment arrangeUpcall(MethodHandle target, MethodType targetType, FunctionDescriptor function, SegmentScope scope) {
62-
return CallArranger.WINDOWS.arrangeUpcall(target, targetType, function, scope);
60+
protected UpcallStubFactory arrangeUpcall(MethodType targetType, FunctionDescriptor function) {
61+
return CallArranger.WINDOWS.arrangeUpcall(targetType, function);
6362
}
6463

6564
public static VaList newVaList(Consumer<VaList.Builder> actions, SegmentScope scope) {
@@ -76,4 +75,4 @@ public static VaList emptyVaList() {
7675
return WindowsAArch64VaList.empty();
7776
}
7877

79-
}
78+
}

0 commit comments

Comments
 (0)