Skip to content

Commit 67dd841

Browse files
committed
8305093: Linker cache should not take layout names into account
Reviewed-by: mcimadamore
1 parent d437c61 commit 67dd841

File tree

2 files changed

+90
-5
lines changed

2 files changed

+90
-5
lines changed

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
3535
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
3636
import jdk.internal.foreign.layout.AbstractLayout;
37+
import jdk.internal.foreign.layout.ValueLayouts;
3738

39+
import java.lang.foreign.AddressLayout;
3840
import java.lang.foreign.GroupLayout;
3941
import java.lang.foreign.MemoryLayout;
4042
import java.lang.foreign.Arena;
@@ -48,6 +50,7 @@
4850
import java.lang.foreign.ValueLayout;
4951
import java.lang.invoke.MethodHandle;
5052
import java.lang.invoke.MethodType;
53+
import java.util.List;
5154
import java.nio.ByteOrder;
5255
import java.util.Objects;
5356

@@ -69,6 +72,7 @@ public MethodHandle downcallHandle(FunctionDescriptor function, Option... option
6972
Objects.requireNonNull(function);
7073
Objects.requireNonNull(options);
7174
checkLayouts(function);
75+
function = stripNames(function);
7276
LinkerOptions optionSet = LinkerOptions.forDowncall(function, options);
7377

7478
return DOWNCALL_CACHE.get(new LinkRequest(function, optionSet), linkRequest -> {
@@ -88,6 +92,7 @@ public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function
8892
Objects.requireNonNull(function);
8993
checkLayouts(function);
9094
SharedUtils.checkExceptions(target);
95+
function = stripNames(function);
9196
LinkerOptions optionSet = LinkerOptions.forUpcall(function, options);
9297

9398
MethodType type = function.toMethodType();
@@ -174,6 +179,32 @@ private static void checkHasNaturalAlignment(MemoryLayout layout) {
174179
}
175180
}
176181

182+
private static MemoryLayout stripNames(MemoryLayout ml) {
183+
// we don't care about transferring alignment and byte order here
184+
// since the linker already restricts those such that they will always be the same
185+
return switch (ml) {
186+
case StructLayout sl -> MemoryLayout.structLayout(stripNames(sl.memberLayouts()));
187+
case UnionLayout ul -> MemoryLayout.unionLayout(stripNames(ul.memberLayouts()));
188+
case SequenceLayout sl -> MemoryLayout.sequenceLayout(sl.elementCount(), stripNames(sl.elementLayout()));
189+
case AddressLayout al -> al.targetLayout()
190+
.map(tl -> al.withoutName().withTargetLayout(stripNames(tl)))
191+
.orElseGet(al::withoutName);
192+
default -> ml.withoutName(); // ValueLayout and PaddingLayout
193+
};
194+
}
195+
196+
private static MemoryLayout[] stripNames(List<MemoryLayout> layouts) {
197+
return layouts.stream()
198+
.map(AbstractLinker::stripNames)
199+
.toArray(MemoryLayout[]::new);
200+
}
201+
202+
private static FunctionDescriptor stripNames(FunctionDescriptor function) {
203+
return function.returnLayout()
204+
.map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts())))
205+
.orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())));
206+
}
207+
177208
private void checkByteOrder(ValueLayout vl) {
178209
if (vl.order() != linkerByteOrder()) {
179210
throw new IllegalArgumentException("Layout does not have the right byte order: " + vl);

test/jdk/java/foreign/TestLinker.java

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,74 @@
3535
import java.lang.foreign.Linker;
3636
import java.lang.invoke.MethodHandle;
3737

38+
import static java.lang.foreign.MemoryLayout.*;
39+
import static java.lang.foreign.ValueLayout.JAVA_CHAR;
40+
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
41+
import static org.testng.Assert.assertSame;
3842
import static org.testng.Assert.assertNotSame;
3943

4044
public class TestLinker extends NativeTestHelper {
4145

42-
@Test
43-
public void testLinkerOptionsCache() {
46+
record LinkRequest(FunctionDescriptor descriptor, Linker.Option... options) {}
47+
48+
@Test(dataProvider = "notSameCases")
49+
public void testLinkerOptionsCache(LinkRequest l1, LinkRequest l2) {
4450
Linker linker = Linker.nativeLinker();
45-
FunctionDescriptor descriptor = FunctionDescriptor.ofVoid(C_INT, C_INT);
46-
MethodHandle mh1 = linker.downcallHandle(descriptor);
47-
MethodHandle mh2 = linker.downcallHandle(descriptor, Linker.Option.firstVariadicArg(1));
51+
MethodHandle mh1 = linker.downcallHandle(l1.descriptor(), l1.options());
52+
MethodHandle mh2 = linker.downcallHandle(l2.descriptor(), l2.options());
4853
// assert that these are 2 distinct link request. No caching allowed
4954
assertNotSame(mh1, mh2);
5055
}
5156

57+
@DataProvider
58+
public static Object[][] notSameCases() {
59+
FunctionDescriptor fd_II_V = FunctionDescriptor.ofVoid(C_INT, C_INT);
60+
return new Object[][]{
61+
{new LinkRequest(fd_II_V), new LinkRequest(fd_II_V, Linker.Option.firstVariadicArg(1))},
62+
{new LinkRequest(FunctionDescriptor.ofVoid(JAVA_SHORT)), new LinkRequest(FunctionDescriptor.ofVoid(JAVA_CHAR))},
63+
{new LinkRequest(FunctionDescriptor.ofVoid(JAVA_SHORT)), new LinkRequest(FunctionDescriptor.ofVoid(JAVA_CHAR))},
64+
};
65+
}
66+
67+
@Test(dataProvider = "namedDescriptors")
68+
public void testNamedLinkerCache(FunctionDescriptor f1, FunctionDescriptor f2) {
69+
Linker linker = Linker.nativeLinker();
70+
MethodHandle mh1 = linker.downcallHandle(f1);
71+
MethodHandle mh2 = linker.downcallHandle(f2);
72+
// assert that these are the same link request, even though layout names differ
73+
assertSame(mh1, mh2);
74+
}
75+
76+
@DataProvider
77+
public static Object[][] namedDescriptors() {
78+
return new Object[][]{
79+
{ FunctionDescriptor.ofVoid(C_INT),
80+
FunctionDescriptor.ofVoid(C_INT.withName("x")) },
81+
{ FunctionDescriptor.ofVoid(structLayout(C_INT)),
82+
FunctionDescriptor.ofVoid(structLayout(C_INT).withName("x")) },
83+
{ FunctionDescriptor.ofVoid(structLayout(C_INT)),
84+
FunctionDescriptor.ofVoid(structLayout(C_INT.withName("x"))) },
85+
{ FunctionDescriptor.ofVoid(structLayout(C_INT, paddingLayout(32), C_LONG_LONG)),
86+
FunctionDescriptor.ofVoid(structLayout(C_INT, paddingLayout(32), C_LONG_LONG.withName("x"))) },
87+
{ FunctionDescriptor.ofVoid(structLayout(C_INT, paddingLayout(32), C_LONG_LONG)),
88+
FunctionDescriptor.ofVoid(structLayout(C_INT, paddingLayout(32).withName("x"), C_LONG_LONG)) },
89+
{ FunctionDescriptor.ofVoid(structLayout(sequenceLayout(1, C_INT))),
90+
FunctionDescriptor.ofVoid(structLayout(sequenceLayout(1, C_INT).withName("x"))) },
91+
{ FunctionDescriptor.ofVoid(structLayout(sequenceLayout(1, C_INT))),
92+
FunctionDescriptor.ofVoid(structLayout(sequenceLayout(1, C_INT.withName("x")))) },
93+
{ FunctionDescriptor.ofVoid(unionLayout(C_INT)),
94+
FunctionDescriptor.ofVoid(unionLayout(C_INT).withName("x")) },
95+
{ FunctionDescriptor.ofVoid(unionLayout(C_INT)),
96+
FunctionDescriptor.ofVoid(unionLayout(C_INT.withName("x"))) },
97+
{ FunctionDescriptor.ofVoid(C_POINTER),
98+
FunctionDescriptor.ofVoid(C_POINTER.withName("x")) },
99+
{ FunctionDescriptor.ofVoid(C_POINTER.withTargetLayout(C_INT)),
100+
FunctionDescriptor.ofVoid(C_POINTER.withTargetLayout(C_INT.withName("x"))) },
101+
{ FunctionDescriptor.ofVoid(C_POINTER.withTargetLayout(C_INT)),
102+
FunctionDescriptor.ofVoid(C_POINTER.withName("x").withTargetLayout(C_INT.withName("x"))) },
103+
};
104+
}
105+
52106
@DataProvider
53107
public static Object[][] invalidIndexCases() {
54108
return new Object[][]{

0 commit comments

Comments
 (0)