@@ -173,8 +173,8 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
173
173
callsitePosition = callsitePositions.getOrElse(call, NoPosition )
174
174
)
175
175
176
- case LMFInvokeDynamic (lmf ) =>
177
- closureInstantiations += lmf
176
+ case LambdaMetaFactoryCall (indy, samMethodType, implMethod, instantiatedMethodType ) =>
177
+ closureInstantiations += LambdaMetaFactoryCall (indy, samMethodType, implMethod, instantiatedMethodType)
178
178
179
179
case _ =>
180
180
}
@@ -242,7 +242,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
242
242
}
243
243
final case class LambdaMetaFactoryCall (indy : InvokeDynamicInsnNode , samMethodType : Type , implMethod : Handle , instantiatedMethodType : Type )
244
244
245
- object LMFInvokeDynamic {
245
+ object LambdaMetaFactoryCall {
246
246
private val lambdaMetaFactoryInternalName : InternalName = " java/lang/invoke/LambdaMetafactory"
247
247
248
248
private val metafactoryHandle = {
@@ -257,69 +257,60 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
257
257
new Handle (Opcodes .H_INVOKESTATIC , lambdaMetaFactoryInternalName, altMetafactoryMethodName, altMetafactoryDesc)
258
258
}
259
259
260
- private def extractLambdaMetaFactoryCall (indy : InvokeDynamicInsnNode ) = {
261
- if (indy.bsm == metafactoryHandle || indy.bsm == altMetafactoryHandle) indy.bsmArgs match {
262
- case Array (samMethodType : Type , implMethod : Handle , instantiatedMethodType : Type , xs@_* ) =>
263
- // LambdaMetaFactory performs a number of automatic adaptations when invoking the lambda
264
- // implementation method (casting, boxing, unboxing, and primitive widening, see Javadoc).
265
- //
266
- // The closure optimizer supports only one of those adaptations: it will cast arguments
267
- // to the correct type when re-writing a closure call to the body method. Example:
268
- //
269
- // val fun: String => String = l => l
270
- // val l = List("")
271
- // fun(l.head)
272
- //
273
- // The samMethodType of Function1 is `(Object)Object`, while the instantiatedMethodType
274
- // is `(String)String`. The return type of `List.head` is `Object`.
275
- //
276
- // The implMethod has the signature `C$anonfun(String)String`.
277
- //
278
- // At the closure callsite, we have an `INVOKEINTERFACE Function1.apply (Object)Object`,
279
- // so the object returned by `List.head` can be directly passed into the call (no cast).
280
- //
281
- // The closure object will cast the object to String before passing it to the implMethod.
282
- //
283
- // When re-writing the closure callsite to the implMethod, we have to insert a cast.
284
- //
285
- // The check below ensures that
286
- // (1) the implMethod type has the expected singature (captured types plus argument types
287
- // from instantiatedMethodType)
288
- // (2) the receiver of the implMethod matches the first captured type
289
- // (3) all parameters that are not the same in samMethodType and instantiatedMethodType
290
- // are reference types, so that we can insert casts to perform the same adaptation
291
- // that the closure object would.
292
-
293
- val isStatic = implMethod.getTag == Opcodes .H_INVOKESTATIC
294
- val indyParamTypes = Type .getArgumentTypes(indy.desc)
295
- val instantiatedMethodArgTypes = instantiatedMethodType.getArgumentTypes
296
- val expectedImplMethodType = {
297
- val paramTypes = (if (isStatic) indyParamTypes else indyParamTypes.tail) ++ instantiatedMethodArgTypes
298
- Type .getMethodType(instantiatedMethodType.getReturnType, paramTypes : _* )
299
- }
300
-
301
- val isIndyLambda = {
302
- Type .getType(implMethod.getDesc) == expectedImplMethodType // (1)
303
- } && {
304
- isStatic || implMethod.getOwner == indyParamTypes(0 ).getInternalName // (2)
305
- } && {
306
- def isReference (t : Type ) = t.getSort == Type .OBJECT || t.getSort == Type .ARRAY
307
- (samMethodType.getArgumentTypes, instantiatedMethodArgTypes).zipped forall {
308
- case (samArgType, instArgType) =>
309
- samArgType == instArgType || isReference(samArgType) && isReference(instArgType) // (3)
260
+ def unapply (insn : AbstractInsnNode ): Option [(InvokeDynamicInsnNode , Type , Handle , Type )] = insn match {
261
+ case indy : InvokeDynamicInsnNode if indy.bsm == metafactoryHandle || indy.bsm == altMetafactoryHandle =>
262
+ indy.bsmArgs match {
263
+ case Array (samMethodType : Type , implMethod : Handle , instantiatedMethodType : Type , xs@_* ) => // xs binding because IntelliJ gets confused about _@_*
264
+ // LambdaMetaFactory performs a number of automatic adaptations when invoking the lambda
265
+ // implementation method (casting, boxing, unboxing, and primitive widening, see Javadoc).
266
+ //
267
+ // The closure optimizer supports only one of those adaptations: it will cast arguments
268
+ // to the correct type when re-writing a closure call to the body method. Example:
269
+ //
270
+ // val fun: String => String = l => l
271
+ // val l = List("")
272
+ // fun(l.head)
273
+ //
274
+ // The samMethodType of Function1 is `(Object)Object`, while the instantiatedMethodType
275
+ // is `(String)String`. The return type of `List.head` is `Object`.
276
+ //
277
+ // The implMethod has the signature `C$anonfun(String)String`.
278
+ //
279
+ // At the closure callsite, we have an `INVOKEINTERFACE Function1.apply (Object)Object`,
280
+ // so the object returned by `List.head` can be directly passed into the call (no cast).
281
+ //
282
+ // The closure object will cast the object to String before passing it to the implMethod.
283
+ //
284
+ // When re-writing the closure callsite to the implMethod, we have to insert a cast.
285
+ //
286
+ // The check below ensures that
287
+ // (1) the implMethod type has the expected singature (captured types plus argument types
288
+ // from instantiatedMethodType)
289
+ // (2) the receiver of the implMethod matches the first captured type
290
+ // (3) all parameters that are not the same in samMethodType and instantiatedMethodType
291
+ // are reference types, so that we can insert casts to perform the same adaptation
292
+ // that the closure object would.
293
+
294
+ val isStatic = implMethod.getTag == Opcodes .H_INVOKESTATIC
295
+ val indyParamTypes = Type .getArgumentTypes(indy.desc)
296
+ val instantiatedMethodArgTypes = instantiatedMethodType.getArgumentTypes
297
+ val expectedImplMethodType = {
298
+ val paramTypes = (if (isStatic) indyParamTypes else indyParamTypes.tail) ++ instantiatedMethodArgTypes
299
+ Type .getMethodType(instantiatedMethodType.getReturnType, paramTypes : _* )
310
300
}
311
- }
312
301
313
- if (isIndyLambda) Some (LambdaMetaFactoryCall (indy, samMethodType, implMethod, instantiatedMethodType))
314
- else None
302
+ val isIndyLambda = (
303
+ Type .getType(implMethod.getDesc) == expectedImplMethodType // (1)
304
+ && (isStatic || implMethod.getOwner == indyParamTypes(0 ).getInternalName) // (2)
305
+ && samMethodType.getArgumentTypes.corresponds(instantiatedMethodArgTypes)((samArgType, instArgType) =>
306
+ samArgType == instArgType || isReference(samArgType) && isReference(instArgType)) // (3)
307
+ )
315
308
316
- case _ => None
317
- }
318
- else None
319
- }
309
+ if (isIndyLambda) Some ((indy, samMethodType, implMethod, instantiatedMethodType))
310
+ else None
320
311
321
- def unapply ( insn : AbstractInsnNode ) : Option [ LambdaMetaFactoryCall ] = insn match {
322
- case indy : InvokeDynamicInsnNode => extractLambdaMetaFactoryCall(indy)
312
+ case _ => None
313
+ }
323
314
case _ => None
324
315
}
325
316
}
0 commit comments