2525
2626package java .lang .runtime ;
2727
28- import jdk .internal .constant .ConstantUtils ;
2928import 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 ;
3530import java .lang .invoke .*;
3631import java .lang .reflect .*;
3732import java .security .AccessController ;
3833import java .security .PrivilegedAction ;
3934import 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 ;
4536import 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 /**
0 commit comments