2222import org .codehaus .groovy .ast .ClassNode ;
2323import org .codehaus .groovy .ast .MethodNode ;
2424import org .codehaus .groovy .ast .Parameter ;
25+ import org .codehaus .groovy .ast .expr .Expression ;
26+ import org .codehaus .groovy .ast .expr .MethodCallExpression ;
27+ import org .codehaus .groovy .ast .stmt .BlockStatement ;
28+ import org .codehaus .groovy .ast .stmt .Statement ;
29+ import org .codehaus .groovy .classgen .asm .WriterController ;
2530import org .codehaus .groovy .syntax .RuntimeParserException ;
2631import org .objectweb .asm .Handle ;
2732import org .objectweb .asm .Opcodes ;
2833import org .objectweb .asm .Type ;
2934
3035import java .util .List ;
36+ import java .util .Objects ;
3137
3238import static org .codehaus .groovy .ast .ClassHelper .getUnwrapper ;
3339import static org .codehaus .groovy .ast .ClassHelper .getWrapper ;
3440import static org .codehaus .groovy .ast .ClassHelper .isDynamicTyped ;
3541import static org .codehaus .groovy .ast .ClassHelper .isPrimitiveType ;
42+ import static org .codehaus .groovy .ast .ClassHelper .OBJECT_TYPE ;
43+ import static org .codehaus .groovy .ast .ClassHelper .SERIALIZEDLAMBDA_TYPE ;
3644import static org .codehaus .groovy .ast .tools .GenericsUtils .hasUnresolvedGenerics ;
45+ import static org .codehaus .groovy .ast .tools .GeneralUtils .andX ;
46+ import static org .codehaus .groovy .ast .tools .GeneralUtils .args ;
47+ import static org .codehaus .groovy .ast .tools .GeneralUtils .boolX ;
48+ import static org .codehaus .groovy .ast .tools .GeneralUtils .callX ;
49+ import static org .codehaus .groovy .ast .tools .GeneralUtils .classX ;
50+ import static org .codehaus .groovy .ast .tools .GeneralUtils .constX ;
51+ import static org .codehaus .groovy .ast .tools .GeneralUtils .eqX ;
52+ import static org .codehaus .groovy .ast .tools .GeneralUtils .ifS ;
53+ import static org .codehaus .groovy .ast .tools .GeneralUtils .nullX ;
54+ import static org .codehaus .groovy .ast .tools .GeneralUtils .returnS ;
55+ import static org .codehaus .groovy .ast .tools .GeneralUtils .varX ;
3756import static org .codehaus .groovy .classgen .asm .BytecodeHelper .getClassInternalName ;
3857import static org .codehaus .groovy .classgen .asm .BytecodeHelper .getMethodDescriptor ;
3958
@@ -59,6 +78,23 @@ default Handle createBootstrapMethod(final boolean isInterface, final boolean se
5978 }
6079
6180 default Object [] createBootstrapMethodArguments (final String abstractMethodDesc , final int insn , final ClassNode methodOwner , final MethodNode methodNode , final Parameter [] parameters , final boolean serializable ) {
81+ Object [] arguments = !serializable ? new Object [3 ] : new Object []{null , null , null , 5 , 0 };
82+
83+ arguments [0 ] = Type .getMethodType (abstractMethodDesc );
84+
85+ arguments [1 ] = new Handle (
86+ insn , // H_INVOKESTATIC or H_INVOKEVIRTUAL or H_INVOKEINTERFACE (GROOVY-9853)
87+ getClassInternalName (methodOwner .getName ()),
88+ methodNode .getName (),
89+ getMethodDescriptor (methodNode ),
90+ methodOwner .isInterface ());
91+
92+ arguments [2 ] = createInstantiatedMethodType (abstractMethodDesc , methodNode , parameters );
93+
94+ return arguments ;
95+ }
96+
97+ default Type createInstantiatedMethodType (final String abstractMethodDesc , final MethodNode methodNode , final Parameter [] parameters ) {
6298 ClassNode returnType = methodNode .getReturnType ();
6399 switch (Type .getReturnType (abstractMethodDesc ).getSort ()) {
64100 case Type .BOOLEAN :
@@ -89,20 +125,7 @@ default Object[] createBootstrapMethodArguments(final String abstractMethodDesc,
89125 returnType = ClassHelper .VOID_TYPE ; // GROOVY-10933
90126 }
91127
92- Object [] arguments = !serializable ? new Object [3 ] : new Object []{null , null , null , 5 , 0 };
93-
94- arguments [0 ] = Type .getMethodType (abstractMethodDesc );
95-
96- arguments [1 ] = new Handle (
97- insn , // H_INVOKESTATIC or H_INVOKEVIRTUAL or H_INVOKEINTERFACE (GROOVY-9853)
98- getClassInternalName (methodOwner .getName ()),
99- methodNode .getName (),
100- getMethodDescriptor (methodNode ),
101- methodOwner .isInterface ());
102-
103- arguments [2 ] = Type .getMethodType (getMethodDescriptor (returnType , parameters ));
104-
105- return arguments ;
128+ return Type .getMethodType (getMethodDescriptor (returnType , parameters ));
106129 }
107130
108131 default ClassNode convertParameterType (final ClassNode parameterType , final ClassNode inferredType ) {
@@ -156,4 +179,92 @@ default Parameter prependParameter(final List<Parameter> parameterList, final St
156179 parameterList .add (0 , parameter );
157180 return parameter ;
158181 }
182+
183+ default SerializedLambdaKey createSerializedLambdaKey (final String abstractMethodDesc , final int implMethodKind , final ClassNode implClass , final MethodNode implMethod , final Parameter [] parameters , final ClassNode functionalType , final MethodNode abstractMethod , final int capturedArgCount ) {
184+ return new SerializedLambdaKey (
185+ implMethodKind ,
186+ getClassInternalName (implClass ),
187+ implMethod .getName (),
188+ getMethodDescriptor (implMethod ),
189+ getClassInternalName (functionalType .redirect ()),
190+ abstractMethod .getName (),
191+ abstractMethodDesc ,
192+ createInstantiatedMethodType (abstractMethodDesc , implMethod , parameters ).getDescriptor (),
193+ capturedArgCount
194+ );
195+ }
196+
197+ default void addDeserializeLambdaDispatcherEntry (final WriterController controller , final Parameter [] parameters , final SerializedLambdaKey key , final MethodNode helperMethod ) {
198+ BlockStatement dispatcher = getOrAddDeserializeLambdaDispatcher (controller , parameters );
199+ MethodCallExpression helperCall = callX (classX (controller .getClassNode ()), helperMethod .getName (), args (varX (parameters [0 ])));
200+ helperCall .setImplicitThis (false );
201+ helperCall .setMethodTarget (helperMethod );
202+
203+ List <Statement > statements = dispatcher .getStatements ();
204+ statements .add (statements .size () - 1 , ifS (boolX (matchesSerializedLambda (varX (parameters [0 ]), key )), returnS (helperCall )));
205+ }
206+
207+ default BlockStatement getOrAddDeserializeLambdaDispatcher (final WriterController controller , final Parameter [] parameters ) {
208+ ClassNode enclosingClass = controller .getClassNode ();
209+ BlockStatement dispatcher = enclosingClass .getNodeMetaData (DeserializeLambdaDispatcher .class );
210+ if (dispatcher != null ) {
211+ return dispatcher ;
212+ }
213+
214+ dispatcher = new BlockStatement ();
215+ dispatcher .addStatement (returnS (callX (classX (ClassHelper .make (Objects .class )), "requireNonNull" , args (nullX (), constX ("Invalid lambda deserialization" )))));
216+
217+ enclosingClass .addSyntheticMethod (
218+ "$deserializeLambda$" ,
219+ Opcodes .ACC_PRIVATE | Opcodes .ACC_STATIC ,
220+ OBJECT_TYPE ,
221+ parameters ,
222+ ClassNode .EMPTY_ARRAY ,
223+ dispatcher );
224+ enclosingClass .putNodeMetaData (DeserializeLambdaDispatcher .class , dispatcher );
225+ return dispatcher ;
226+ }
227+
228+ default Expression matchesSerializedLambda (final Expression serializedLambda , final SerializedLambdaKey key ) {
229+ return andX (
230+ eqX (callX (serializedLambda , "getImplMethodKind" ), constX (key .implMethodKind (), true )),
231+ andX (
232+ eqX (callX (serializedLambda , "getImplClass" ), constX (key .implClass ())),
233+ andX (
234+ eqX (callX (serializedLambda , "getImplMethodName" ), constX (key .implMethodName ())),
235+ andX (
236+ eqX (callX (serializedLambda , "getImplMethodSignature" ), constX (key .implMethodSignature ())),
237+ andX (
238+ eqX (callX (serializedLambda , "getFunctionalInterfaceClass" ), constX (key .functionalInterfaceClass ())),
239+ andX (
240+ eqX (callX (serializedLambda , "getFunctionalInterfaceMethodName" ), constX (key .functionalInterfaceMethodName ())),
241+ andX (
242+ eqX (callX (serializedLambda , "getFunctionalInterfaceMethodSignature" ), constX (key .functionalInterfaceMethodSignature ())),
243+ andX (
244+ eqX (callX (serializedLambda , "getInstantiatedMethodType" ), constX (key .instantiatedMethodType ())),
245+ eqX (callX (serializedLambda , "getCapturedArgCount" ), constX (key .capturedArgCount (), true ))
246+ )
247+ )
248+ )
249+ )
250+ )
251+ )
252+ )
253+ );
254+ }
255+
256+ default Parameter [] createDeserializeLambdaMethodParams () {
257+ return new Parameter []{new Parameter (SERIALIZEDLAMBDA_TYPE , "serializedLambda" )};
258+ }
259+
260+ final class DeserializeLambdaDispatcher {
261+ private DeserializeLambdaDispatcher () {
262+ }
263+ }
264+
265+ record SerializedLambdaKey (int implMethodKind , String implClass , String implMethodName , String implMethodSignature ,
266+ String functionalInterfaceClass , String functionalInterfaceMethodName ,
267+ String functionalInterfaceMethodSignature , String instantiatedMethodType ,
268+ int capturedArgCount ) {
269+ }
159270}
0 commit comments