Skip to content

Commit b913695

Browse files
committed
Second Approach: rely on the mangled name
1 parent 81a68a6 commit b913695

File tree

7 files changed

+105
-76
lines changed

7 files changed

+105
-76
lines changed

src/java.base/share/classes/java/lang/reflect/Deconstructor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package java.lang.reflect;
22

33
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
6+
import static java.lang.runtime.PatternBytecodeName.mangle;
47

58
/**
69
* {@code Deconstructor} provides information about, and access to, a single
@@ -95,4 +98,9 @@ Deconstructor<T> copy() {
9598
res.root = this;
9699
return res;
97100
}
101+
102+
private static final String DINIT = "\\^dinit\\_";
103+
String getMangledName() {
104+
return DINIT + ":" + super.getMangledName();
105+
}
98106
}

src/java.base/share/classes/java/lang/runtime/PatternBootstraps.java

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,14 @@
2525

2626
package java.lang.runtime;
2727

28-
import jdk.internal.constant.ConstantUtils;
2928
import jdk.internal.misc.PreviewFeatures;
3029

31-
import java.lang.Enum.EnumDesc;
32-
import java.lang.classfile.ClassFile;
33-
import java.lang.constant.ClassDesc;
34-
import java.lang.constant.MethodTypeDesc;
3530
import java.lang.invoke.*;
3631
import java.lang.reflect.*;
3732
import java.security.AccessController;
3833
import java.security.PrivilegedAction;
3934
import java.util.*;
40-
import java.util.function.BiPredicate;
41-
import java.util.stream.Collectors;
4235

43-
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
44-
import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
4536
import static java.util.Objects.requireNonNull;
4637

4738
/**
@@ -60,6 +51,7 @@ private PatternBootstraps() {
6051
private static final Object SENTINEL = new Object();
6152
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
6253
private static final boolean previewEnabled = PreviewFeatures.isEnabled();
54+
private static final String DINIT = "\\^dinit\\_";
6355

6456
private static class StaticHolders {
6557
private static final MethodHandle SYNTHETIC_PATTERN;
@@ -97,7 +89,6 @@ private static class StaticHolders {
9789
* @param invocationType The invocation type of the {@code CallSite} with one parameter,
9890
* a reference type, and an {@code Object} as a return type.
9991
* @param mangledName The mangled name of the method declaration that will act as a pattern.
100-
* @param needsStatic Guide the translation
10192
* @return a {@code CallSite} returning the first matching element as described above
10293
* @throws NullPointerException if any argument is {@code null}
10394
* @throws IllegalArgumentException if the invocation type is not a method type of first parameter of a reference type,
@@ -108,72 +99,101 @@ private static class StaticHolders {
10899
public static CallSite invokePattern(MethodHandles.Lookup lookup,
109100
String invocationName,
110101
MethodType invocationType,
111-
String mangledName,
112-
int needsStatic) {
113-
if (invocationType.parameterCount() == 2) {
114-
Class<?> receiverType = invocationType.parameterType(0);
115-
Class<?> matchCandidateType = invocationType.parameterType(1);
116-
if ((!invocationType.returnType().equals(Object.class)))
117-
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
118-
119-
MethodHandle target = null;
120-
try {
121-
if (needsStatic == 1) {
122-
// Attempt 1: discover the pattern declaration
102+
String mangledName) {
103+
MethodHandle target = null;
104+
105+
switch (detectPatternUseSite(invocationType, mangledName)) {
106+
case Deconstructor -> {
107+
Class<?> receiverType = invocationType.parameterType(0);
108+
Class<?> matchCandidateType = invocationType.parameterType(1);
109+
try {
110+
// Attempt 1: discover the deconstructor
123111
target = lookup.findStatic(receiverType, mangledName, MethodType.methodType(Object.class, receiverType, matchCandidateType));
112+
} catch (Throwable t) {
113+
// Attempt 2: synthesize the pattern declaration from the record components
114+
if (!matchCandidateType.isRecord() || !receiverType.equals(matchCandidateType)) {
115+
throw new IllegalArgumentException("Implicit deconstructor invocation with erroneous match-candidate type or received type");
116+
}
117+
118+
String expectedMangledName = DINIT + ':' + PatternBytecodeName.mangle(matchCandidateType,
119+
Arrays.stream(matchCandidateType.getRecordComponents())
120+
.map(RecordComponent::getType)
121+
.toArray(Class<?>[]::new));
122+
123+
if (!expectedMangledName.equals(mangledName)) {
124+
throw new IllegalArgumentException("Unexpected deconstructor at use site: " + mangledName + "(was expecting: " + expectedMangledName + ")");
125+
}
126+
127+
target = calculateSyntheticPatternMT(invocationType, matchCandidateType);
124128
}
125-
else {
129+
}
130+
case InstancePattern -> {
131+
Class<?> receiverType = invocationType.parameterType(0);
132+
Class<?> matchCandidateType = invocationType.parameterType(1);
133+
try {
126134
target = lookup.findVirtual(receiverType, mangledName, MethodType.methodType(Object.class, matchCandidateType));
127135
}
128-
return new ConstantCallSite(target);
129-
} catch (Throwable t) {
130-
// Attempt 2: synthesize the pattern declaration from the record components
131-
if (!matchCandidateType.isRecord() || !receiverType.equals(matchCandidateType)) {
132-
throw new IllegalArgumentException("Implicit pattern invocation with erroneous match-candidate type or received type");
136+
catch (Throwable t) {
137+
throw new IllegalArgumentException("Unexpected instance pattern");
133138
}
134-
135-
String expectedMangledName = PatternBytecodeName.mangle(matchCandidateType,
136-
Arrays.stream(matchCandidateType.getRecordComponents())
137-
.map(RecordComponent::getType)
138-
.toArray(Class<?>[]::new));
139-
140-
if (!expectedMangledName.equals(mangledName)) {
141-
throw new IllegalArgumentException("Unexpected pattern at use site: " + mangledName + "(was expecting: " + expectedMangledName + ")");
139+
}
140+
case StaticPattern -> {
141+
Class<?> matchCandidateType = invocationType.parameterType(0);
142+
try {
143+
target = lookup.findStatic(matchCandidateType, mangledName, MethodType.methodType(Object.class, matchCandidateType));
142144
}
145+
catch (Throwable t) {
146+
throw new IllegalArgumentException("Unexpected static pattern");
147+
}
148+
}
149+
}
143150

144-
@SuppressWarnings("removal")
145-
final RecordComponent[] components = AccessController.doPrivileged(
146-
(PrivilegedAction<RecordComponent[]>) matchCandidateType::getRecordComponents);
151+
return new ConstantCallSite(target);
152+
}
147153

148-
Method[] accessors = Arrays.stream(components).map(c -> {
149-
Method accessor = c.getAccessor();
150-
accessor.setAccessible(true);
151-
return accessor;
152-
}).toArray(Method[]::new);
154+
private static MethodHandle calculateSyntheticPatternMT(MethodType invocationType, Class<?> matchCandidateType) {
155+
@SuppressWarnings("removal") final RecordComponent[] components = AccessController.doPrivileged(
156+
(PrivilegedAction<RecordComponent[]>) matchCandidateType::getRecordComponents);
153157

154-
Class<?>[] ctypes = Arrays.stream(components).map(c -> c.getType()).toArray(Class<?>[]::new);
158+
Method[] accessors = Arrays.stream(components).map(c -> {
159+
Method accessor = c.getAccessor();
160+
accessor.setAccessible(true);
161+
return accessor;
162+
}).toArray(Method[]::new);
155163

156-
Carriers.CarrierElements carrierElements = Carriers.CarrierFactory.of(ctypes);
164+
Class<?>[] ctypes = Arrays.stream(components).map(c -> c.getType()).toArray(Class<?>[]::new);
157165

158-
MethodHandle initializingConstructor = carrierElements.initializingConstructor();
166+
Carriers.CarrierElements carrierElements = Carriers.CarrierFactory.of(ctypes);
159167

160-
MethodHandle carrierCreator = initializingConstructor.asSpreader(Object[].class, ctypes.length);
168+
MethodHandle initializingConstructor = carrierElements.initializingConstructor();
161169

162-
target =
163-
MethodHandles.dropArguments(
164-
MethodHandles.insertArguments(StaticHolders.SYNTHETIC_PATTERN,
165-
0,
166-
accessors,
167-
carrierCreator),
168-
1,
169-
Object.class).asType(invocationType);
170+
MethodHandle carrierCreator = initializingConstructor.asSpreader(Object[].class, ctypes.length);
170171

171-
return new ConstantCallSite(target);
172-
}
173-
}
172+
return MethodHandles.dropArguments(
173+
MethodHandles.insertArguments(StaticHolders.SYNTHETIC_PATTERN,
174+
0,
175+
accessors,
176+
carrierCreator),
177+
1,
178+
Object.class).asType(invocationType);
179+
}
174180

175-
// todo: static patterns will expect one parameter
176-
throw new IllegalStateException("Pattern Invocation Illegal State");
181+
enum PatternUseSite {
182+
Deconstructor,
183+
InstancePattern,
184+
StaticPattern
185+
}
186+
static PatternUseSite detectPatternUseSite(MethodType invocationType,
187+
String mangledName) {
188+
if (invocationType.parameterCount() == 2) {
189+
return mangledName.startsWith(DINIT + ':') ? PatternUseSite.Deconstructor : PatternUseSite.InstancePattern;
190+
} else if (invocationType.parameterCount() == 1) {
191+
return PatternUseSite.StaticPattern;
192+
} else if ((!invocationType.returnType().equals(Object.class))) {
193+
throw new IllegalArgumentException("Illegal return type: " + invocationType);
194+
} else {
195+
throw new IllegalArgumentException("Illegal invocation type " + invocationType);
196+
}
177197
}
178198

179199
/**

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,18 +2099,18 @@ public Name externalName(Types types) {
20992099

21002100
private Name mangledBytecodePatternName(Types types) {
21012101
List<Type> bindingTypes = ((PatternType) this.type).erasedBindingTypes;
2102-
2103-
List<String> parts = bindingTypes.map(type -> {
2102+
List<String> bindingTypesStringParts = bindingTypes.map(type -> {
21042103
var g = new UnSharedSignatureGenerator(types);
21052104
g.assembleSig(type);
21062105
String mangled = name.table.names.fromString(BytecodeName.toBytecodeName(g.toName(name.table.names).toString())).toString();
21072106
mangled = mangled.toString().replaceFirst("\\\\=", "");
21082107
return mangled;
21092108
});
2109+
String bindingTypesString = String.join(":", bindingTypesStringParts);
21102110

2111-
String postFix = String.join(":", parts);
2111+
String patternNameString = isDeconstructor() ? BytecodeName.toBytecodeName(name.table.names.dinit.toString()) + ":" + owner.name.toString() : name.toString();
21122112

2113-
return name.table.names.fromString((isDeconstructor() ? owner.name.toString() : name) + ":" + postFix);
2113+
return name.table.names.fromString(patternNameString + ":" + bindingTypesString);
21142114
}
21152115

21162116
static class UnSharedSignatureGenerator extends Types.SignatureGenerator {

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -538,16 +538,15 @@ private JCMethodInvocation generatePatternCall(JCRecordPattern recordPattern, Bi
538538
List<Type> staticArgTypes = List.of(syms.methodHandleLookupType,
539539
syms.stringType,
540540
syms.methodTypeType,
541-
syms.stringType,
542-
syms.intType);
541+
syms.stringType);
543542

544543
MethodSymbol bsm = rs.resolveInternalMethod(
545544
recordPattern.pos(), env, syms.patternBootstrapsType,
546545
names.invokePattern, staticArgTypes, List.nil());
547546

548547
List<JCExpression> invocationParams = List.of(make.Ident(matchCandidate));
549548
List<Type> invocationParamTypes;
550-
if (true /*is instance pattern*/) {
549+
if (true) {
551550
if (recordPattern.deconstructor instanceof JCFieldAccess acc &&
552551
!TreeInfo.isStaticSelector(acc.selected, names)) {
553552
invocationParamTypes = List.of(/*receiver:*/acc.selected.type,
@@ -570,10 +569,8 @@ private JCMethodInvocation generatePatternCall(JCRecordPattern recordPattern, Bi
570569
);
571570

572571
String mangledName = ((MethodSymbol)(recordPattern.patternDeclaration.baseSymbol())).externalName(types).toString();
573-
int needsStatic = recordPattern.patternDeclaration.baseSymbol().isStatic() || recordPattern.patternDeclaration.baseSymbol().isDeconstructor() ? 1: 0;
574572
LoadableConstant[] staticArgValues = new LoadableConstant[] {
575-
LoadableConstant.String(mangledName),
576-
LoadableConstant.Int(needsStatic)
573+
LoadableConstant.String(mangledName)
577574
};
578575

579576
DynamicMethodSymbol dynSym = new DynamicMethodSymbol(names.invokePattern,

src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public static Names instance(Context context) {
113113
public final Name values;
114114
public final Name readResolve;
115115
public final Name readObject;
116+
public final Name dinit;
116117

117118
// class names
118119
public final Name java_io_Serializable;
@@ -314,6 +315,7 @@ public Names(Context context) {
314315
readResolve = fromString("readResolve");
315316
readObject = fromString("readObject");
316317
dollarThis = fromString("$this");
318+
dinit = fromString("<dinit>");
317319

318320
// class names
319321
java_io_Serializable = fromString("java.io.Serializable");

test/jdk/java/lang/runtime/PatternBootstrapsTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@
5454
public class PatternBootstrapsTest {
5555

5656
public static final MethodHandle INVK_PATTERN;
57+
private static final String DINIT = "\\^dinit\\_";
58+
5759
static {
5860
try {
5961
INVK_PATTERN = MethodHandles.lookup().findStatic(PatternBootstraps.class, "invokePattern",
60-
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, String.class, int.class));
62+
MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, String.class));
6163
}
6264
catch (ReflectiveOperationException e) {
6365
throw new AssertionError("Should not happen", e);
@@ -80,13 +82,13 @@ public pattern R2(int x, int y) {
8082

8183
private void testPatternInvocation(Object target, Class<?> targetType, String mangledName, int componentNo, int result) throws Throwable {
8284
MethodType dtorType = MethodType.methodType(Object.class, targetType, targetType);
83-
MethodHandle indy = ((CallSite) INVK_PATTERN.invoke(MethodHandles.lookup(), "", dtorType, mangledName, 1)).dynamicInvoker();
85+
MethodHandle indy = ((CallSite) INVK_PATTERN.invoke(MethodHandles.lookup(), "", dtorType, mangledName)).dynamicInvoker();
8486
List<MethodHandle> components = Carriers.components(MethodType.methodType(Object.class, int.class, int.class));
8587
assertEquals((int) components.get(componentNo).invokeExact(indy.invoke(target, target)), result);
8688
}
8789

8890
public void testPatternInvocations() throws Throwable {
89-
testPatternInvocation(new R(1, 2), R.class, "R:I:I", 0, 1);
90-
testPatternInvocation(new R2(1, 2), R2.class, "R2:I:I", 0, 1);
91+
testPatternInvocation(new R(1, 2), R.class, DINIT + ":R:I:I", 0, 1);
92+
testPatternInvocation(new R2(1, 2), R2.class, DINIT + ":R2:I:I", 0, 1);
9193
}
9294
}

test/langtools/tools/javac/patterns/declarations/PatternDeclarationsBytecodeTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public pattern Test(String name, String username) {
9494
.run()
9595
.getOutput(Task.OutputKind.DIRECT);
9696

97-
if (!javapOut.contains("public static java.lang.Object Test:Ljava\\|lang\\|String\\?:Ljava\\|lang\\|String\\?(test.Test, test.Test)"))
97+
if (!javapOut.contains("public static java.lang.Object \\^dinit\\_:Test:Ljava\\|lang\\|String\\?:Ljava\\|lang\\|String\\?(test.Test, test.Test)"))
9898
throw new AssertionError("Wrongly generated signature of pattern declaration:\n" + javapOut);
9999
}
100100
}

0 commit comments

Comments
 (0)