Skip to content

Commit 0533a3d

Browse files
committed
Lambda impl methods static and more stably named
The body of lambdas is compiled into a synthetic method in the enclosing class. Previously, this method was a public virtual method named `fully$qualified$Class$$anonfun$n`. For lambdas that didn't capture a `this` reference, a static method was used. This commit changes two aspects. Firstly, all lambda impl methods are now emitted static. An extra parameter is added to those that require a this reference. This is an improvement as it: - allows, shorter, more readable names for the lambda impl method - avoids pollution of the vtable of the class. Note that javac uses private instance methods, rather than public static methods. If we followed its lead, we would be unable to support important use cases in our inliner Secondly, the name of the enclosing method has been included in the name of the lambda impl method to improve debuggability and to improve serialization compatibility. The serialization improvement comes from the way that fresh names for the impl methods are allocated: adding or removing lambdas in methods not named "foo" won't change the numbering of the `anonfun$foo$n` impl methods from methods named "foo". This is in line with user expectations about anonymous class and lambda serialization stability. Brian Goetz has described this tricky area well in: http://cr.openjdk.java.net/~briangoetz/eg-attachments/lambda-serialization.html This commit doesn't go as far a Javac, we don't use the hash of the lambda type info, param names, etc to map to a lambda impl method name. As such, we are more prone to the type-1 and -2 failures described there. However, our Scala 2.11.8 has similar characteristics, so we aren't going backwards. Special case in the naming: Use "new" rather than "<init>" for constructor enclosed lambdas, as javac does. I have also changed the way that "delambdafy target" methods are identifed. Rather than relying on the naming convention, I have switched to using a symbol attachment. The assumption is that we only need to identify them from within the same compilation unit. This means we can distinguish impl metbods for expanded functions (ones called from an `apply` method of an ahead-of-time expanded anonfun class), from those that truly end up as targets for lambda metafactory. Only the latter are translated to static methods in this patch.
1 parent 7b132f3 commit 0533a3d

20 files changed

+153
-68
lines changed

src/compiler/scala/tools/nsc/ast/TreeGen.scala

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
238238
* (outside the synchronized block).
239239
*
240240
* The idiom works only if the condition is using a volatile field.
241-
* @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
241+
*
242+
* @see http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
242243
*/
243244
def mkSynchronizedCheck(clazz: Symbol, cond: Tree, syncBody: List[Tree], stats: List[Tree]): Tree =
244245
mkSynchronizedCheck(mkAttributedThis(clazz), cond, syncBody, stats)
@@ -274,8 +275,19 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
274275
}
275276

276277
// used to create the lifted method that holds a function's body
277-
def mkLiftedFunctionBodyMethod(localTyper: analyzer.Typer)(owner: Symbol, fun: Function) =
278-
mkMethodForFunctionBody(localTyper)(owner, fun, nme.ANON_FUN_NAME)(additionalFlags = ARTIFACT)
278+
def mkLiftedFunctionBodyMethod(localTyper: global.analyzer.Typer)(owner: global.Symbol, fun: global.Function) = {
279+
def nonLocalEnclosingMember(sym: Symbol): Symbol = {
280+
if (sym.isLocalDummy) sym.enclClass.primaryConstructor
281+
else if (sym.isLocalToBlock) nonLocalEnclosingMember(sym.originalOwner)
282+
else sym
283+
}
284+
val ownerName = nonLocalEnclosingMember(fun.symbol.originalOwner).name match {
285+
case nme.CONSTRUCTOR => nme.NEWkw // do as javac does for the suffix, prefer "new" to "$lessinit$greater$1"
286+
case x => x
287+
}
288+
val newName = nme.ANON_FUN_NAME.append(nme.NAME_JOIN_STRING).append(ownerName)
289+
mkMethodForFunctionBody(localTyper)(owner, fun, newName)(additionalFlags = ARTIFACT)
290+
}
279291

280292

281293
/**
@@ -310,6 +322,38 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL {
310322
newDefDef(methSym, moveToMethod(useMethodParams(fun.body)))(tpt = TypeTree(resTp))
311323
}
312324

325+
/**
326+
* Create a new `DefDef` based on `orig` with an explicit self parameter.
327+
*
328+
* Details:
329+
* - Must by run after erasure
330+
* - If `maybeClone` is the identity function, this runs "in place"
331+
* and mutates the symbol of `orig`. `orig` should be discarded
332+
* - Symbol owners and returns are substituted, as are parameter symbols
333+
* - Recursive calls are not rewritten. This is correct if we assume
334+
* that we either:
335+
* - are in "in-place" mode, but can guarantee that no recursive calls exists
336+
* - are associating the RHS with a cloned symbol, but intend for the original
337+
* method to remain and for recursive calls to target it.
338+
*/
339+
final def mkStatic(orig: DefDef, maybeClone: Symbol => Symbol): DefDef = {
340+
assert(phase.erasedTypes, phase)
341+
assert(!orig.symbol.hasFlag(SYNCHRONIZED), orig.symbol.defString)
342+
val origSym = orig.symbol
343+
val origParams = orig.symbol.info.params
344+
val newSym = maybeClone(orig.symbol)
345+
newSym.setFlag(STATIC)
346+
// Add an explicit self parameter
347+
val selfParamSym = newSym.newSyntheticValueParam(newSym.owner.typeConstructor, nme.SELF)
348+
newSym.updateInfo(newSym.info match {
349+
case mt @ MethodType(params, res) => copyMethodType(mt, selfParamSym :: params, res)
350+
})
351+
val selfParam = ValDef(selfParamSym)
352+
val rhs = orig.rhs.substituteThis(newSym.owner, atPos(newSym.pos)(gen.mkAttributedIdent(selfParamSym)))
353+
.substituteSymbols(origParams, newSym.info.params.drop(1)).changeOwner(origSym -> newSym)
354+
treeCopy.DefDef(orig, orig.mods, orig.name, orig.tparams, (selfParam :: orig.vparamss.head) :: Nil, orig.tpt, rhs).setSymbol(newSym)
355+
}
356+
313357
// TODO: the rewrite to AbstractFunction is superfluous once we compile FunctionN to a SAM type (aka functional interface)
314358
def functionClassType(fun: Function): Type =
315359
if (isFunctionType(fun.tpe)) abstractFunctionType(fun.vparams.map(_.symbol.tpe), fun.body.tpe.deconst)

src/compiler/scala/tools/nsc/backend/jvm/analysis/BackendUtils.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class BackendUtils[BT <: BTypes](val btypes: BT) {
121121

122122
def getBoxedUnit: FieldInsnNode = new FieldInsnNode(GETSTATIC, srBoxedUnitRef.internalName, "UNIT", srBoxedUnitRef.descriptor)
123123

124-
private val anonfunAdaptedName = """.*\$anonfun\$\d+\$adapted""".r
124+
private val anonfunAdaptedName = """.*\$anonfun\$.*\$\d+\$adapted""".r
125125
def hasAdaptedImplMethod(closureInit: ClosureInstantiation): Boolean = {
126126
isBuiltinFunctionType(Type.getReturnType(closureInit.lambdaMetaFactoryCall.indy.desc).getInternalName) &&
127127
anonfunAdaptedName.pattern.matcher(closureInit.lambdaMetaFactoryCall.implMethod.getName).matches

src/compiler/scala/tools/nsc/transform/Delambdafy.scala

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,18 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
6161

6262
private def mkLambdaMetaFactoryCall(fun: Function, target: Symbol, functionalInterface: Symbol, samUserDefined: Symbol, isSpecialized: Boolean): Tree = {
6363
val pos = fun.pos
64+
def isSelfParam(p: Symbol) = p.isSynthetic && p.name == nme.SELF
65+
val hasSelfParam = isSelfParam(target.firstParam)
66+
6467
val allCapturedArgRefs = {
6568
// find which variables are free in the lambda because those are captures that need to be
6669
// passed into the constructor of the anonymous function class
6770
val captureArgs = FreeVarTraverser.freeVarsOf(fun).iterator.map(capture =>
6871
gen.mkAttributedRef(capture) setPos pos
6972
).toList
7073

71-
if (target hasFlag STATIC) captureArgs // no `this` reference needed
74+
if (!hasSelfParam) captureArgs.filterNot(arg => isSelfParam(arg.symbol))
75+
else if (currentMethod.hasFlag(Flags.STATIC)) captureArgs
7276
else (gen.mkAttributedThis(fun.symbol.enclClass) setPos pos) :: captureArgs
7377
}
7478

@@ -179,7 +183,7 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
179183
val numCaptures = targetParams.length - functionParamTypes.length
180184
val (targetCapturedParams, targetFunctionParams) = targetParams.splitAt(numCaptures)
181185

182-
val methSym = oldClass.newMethod(target.name.append("$adapted").toTermName, target.pos, target.flags | FINAL | ARTIFACT)
186+
val methSym = oldClass.newMethod(target.name.append("$adapted").toTermName, target.pos, target.flags | FINAL | ARTIFACT | STATIC)
183187
val bridgeCapturedParams = targetCapturedParams.map(param => methSym.newSyntheticValueParam(param.tpe, param.name.toTermName))
184188
val bridgeFunctionParams =
185189
map2(targetFunctionParams, bridgeParamTypes)((param, tp) => methSym.newSyntheticValueParam(tp, param.name.toTermName))
@@ -223,10 +227,8 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
223227

224228
private def transformFunction(originalFunction: Function): Tree = {
225229
val target = targetMethod(originalFunction)
226-
target.makeNotPrivate(target.owner)
227-
228-
// must be done before calling createBoxingBridgeMethod and mkLambdaMetaFactoryCall
229-
if (!(target hasFlag STATIC) && !methodReferencesThis(target)) target setFlag STATIC
230+
assert(target.hasFlag(Flags.STATIC))
231+
target.setFlag(notPRIVATE)
230232

231233
val funSym = originalFunction.tpe.typeSymbolDirect
232234
// The functional interface that can be used to adapt the lambda target method `target` to the given function type.
@@ -252,11 +254,22 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre
252254
// here's the main entry point of the transform
253255
override def transform(tree: Tree): Tree = tree match {
254256
// the main thing we care about is lambdas
255-
case fun: Function => super.transform(transformFunction(fun))
257+
case fun: Function =>
258+
super.transform(transformFunction(fun))
256259
case Template(_, _, _) =>
260+
def pretransform(tree: Tree): Tree = tree match {
261+
case dd: DefDef if dd.symbol.isDelambdafyTarget =>
262+
if (!dd.symbol.hasFlag(STATIC) && methodReferencesThis(dd.symbol)) {
263+
gen.mkStatic(dd, sym => sym)
264+
} else {
265+
dd.symbol.setFlag(STATIC)
266+
dd
267+
}
268+
case t => t
269+
}
257270
try {
258271
// during this call boxingBridgeMethods will be populated from the Function case
259-
val Template(parents, self, body) = super.transform(tree)
272+
val Template(parents, self, body) = super.transform(deriveTemplate(tree)(_.mapConserve(pretransform)))
260273
Template(parents, self, body ++ boxingBridgeMethods)
261274
} finally boxingBridgeMethods.clear()
262275
case _ => super.transform(tree)

src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
13291329
class SpecializationDuplicator(casts: Map[Symbol, Type]) extends Duplicator(casts) {
13301330
override def retyped(context: Context, tree: Tree, oldThis: Symbol, newThis: Symbol, env: scala.collection.Map[Symbol, Type]): Tree =
13311331
enteringSpecialize(super.retyped(context, tree, oldThis, newThis, env))
1332+
13321333
}
13331334

13341335
/** A tree symbol substituter that substitutes on type skolems.

src/compiler/scala/tools/nsc/transform/UnCurry.scala

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ abstract class UnCurry extends InfoTransform
213213
// Expand the function body into an anonymous class
214214
gen.expandFunction(localTyper)(fun, inConstructorFlag)
215215
} else {
216+
val mustExpand = mustExpandFunction(fun)
216217
// method definition with the same arguments, return type, and body as the original lambda
217218
val liftedMethod = gen.mkLiftedFunctionBodyMethod(localTyper)(fun.symbol.owner, fun)
218219

@@ -221,11 +222,18 @@ abstract class UnCurry extends InfoTransform
221222
gen.mkForwarder(gen.mkAttributedRef(liftedMethod.symbol), (fun.vparams map (_.symbol)) :: Nil)
222223
))
223224

225+
if (!mustExpand) {
226+
liftedMethod.symbol.updateAttachment(DelambdafyTarget)
227+
liftedMethod.updateAttachment(DelambdafyTarget)
228+
}
229+
224230
val typedNewFun = localTyper.typedPos(fun.pos)(Block(liftedMethod, super.transform(newFun)))
225-
if (mustExpandFunction(fun)) {
231+
if (mustExpand) {
226232
val Block(stats, expr : Function) = typedNewFun
227233
treeCopy.Block(typedNewFun, stats, gen.expandFunction(localTyper)(expr, inConstructorFlag))
228-
} else typedNewFun
234+
} else {
235+
typedNewFun
236+
}
229237
}
230238

231239
def transformArgs(pos: Position, fun: Symbol, args: List[Tree], formals: List[Type]) = {
@@ -341,13 +349,18 @@ abstract class UnCurry extends InfoTransform
341349

342350
private def isSelfSynchronized(ddef: DefDef) = ddef.rhs match {
343351
case Apply(fn @ TypeApply(Select(sel, _), _), _) =>
344-
fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait
352+
fn.symbol == Object_synchronized && sel.symbol == ddef.symbol.enclClass && !ddef.symbol.enclClass.isTrait &&
353+
!ddef.symbol.isDelambdafyTarget /* these become static later, unsuitable for ACC_SYNCHRONIZED */
345354
case _ => false
346355
}
347356

348357
/** If an eligible method is entirely wrapped in a call to synchronized
349358
* locked on the same instance, remove the synchronized scaffolding and
350359
* mark the method symbol SYNCHRONIZED for bytecode generation.
360+
*
361+
* Delambdafy targets are deemed ineligible as the Delambdafy phase will
362+
* replace `this.synchronized` with `$this.synchronzed` now that it emits
363+
* all lambda impl methods as static.
351364
*/
352365
private def translateSynchronized(tree: Tree) = tree match {
353366
case dd @ DefDef(_, _, _, _, _, Apply(fn, body :: Nil)) if isSelfSynchronized(dd) =>

src/compiler/scala/tools/nsc/typechecker/Duplicators.scala

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ abstract class Duplicators extends Analyzer {
229229

230230
case ddef @ DefDef(_, _, _, _, tpt, rhs) =>
231231
ddef.tpt modifyType fixType
232-
super.typed(ddef.clearType(), mode, pt)
232+
val result = super.typed(ddef.clearType(), mode, pt)
233+
// TODO this is a hack, we really need a cleaner way to transport symbol attachments to duplicated methods
234+
// bodies in specialized subclasses.
235+
if (ddef.hasAttachment[DelambdafyTarget.type])
236+
result.symbol.updateAttachment(DelambdafyTarget)
237+
result
233238

234239
case fun: Function =>
235240
debuglog("Clearing the type and retyping Function: " + fun)

src/reflect/scala/reflect/internal/StdAttachments.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ trait StdAttachments {
5151
*/
5252
case class SAMFunction(samTp: Type, sam: Symbol) extends PlainAttachment
5353

54+
case object DelambdafyTarget extends PlainAttachment
55+
5456
/** When present, indicates that the host `Ident` has been created from a backquoted identifier.
5557
*/
5658
case object BackquotedIdentifierAttachment extends PlainAttachment

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
807807

808808
final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME)
809809
final def isDelambdafyFunction = isSynthetic && (name containsName tpnme.DELAMBDAFY_LAMBDA_CLASS_NAME)
810-
final def isDelambdafyTarget = isArtifact && isMethod && (name containsName tpnme.ANON_FUN_NAME)
810+
final def isDelambdafyTarget = isArtifact && isMethod && hasAttachment[DelambdafyTarget.type]
811811
final def isDefinedInPackage = effectiveOwner.isPackageClass
812812
final def needsFlatClasses = phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass
813813

src/reflect/scala/reflect/runtime/JavaUniverseForce.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
3838
this.FixedMirrorTypeCreator
3939
this.CompoundTypeTreeOriginalAttachment
4040
this.SAMFunction
41+
this.DelambdafyTarget
4142
this.BackquotedIdentifierAttachment
4243
this.ForAttachment
4344
this.SyntheticUnitAttachment

test/files/run/delambdafy_t6028.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ package <empty> {
1111
def foo(methodParam: String): Function0 = {
1212
val methodLocal: String = "";
1313
{
14-
(() => T.this.$anonfun$1(methodParam, methodLocal))
14+
(() => T.this.$anonfun$foo$1(methodParam, methodLocal))
1515
}
1616
};
1717
def bar(barParam: String): Object = {
@@ -21,10 +21,10 @@ package <empty> {
2121
def tryy(tryyParam: String): Function0 = {
2222
var tryyLocal: runtime.ObjectRef = scala.runtime.ObjectRef.create("");
2323
{
24-
(() => T.this.$anonfun$2(tryyParam, tryyLocal))
24+
(() => T.this.$anonfun$tryy$1(tryyParam, tryyLocal))
2525
}
2626
};
27-
final <artifact> private[this] def $anonfun$1(methodParam$1: String, methodLocal$1: String): String = T.this.classParam.+(T.this.field()).+(methodParam$1).+(methodLocal$1);
27+
final <artifact> private[this] def $anonfun$foo$1(methodParam$1: String, methodLocal$1: String): String = T.this.classParam.+(T.this.field()).+(methodParam$1).+(methodLocal$1);
2828
abstract trait MethodLocalTrait$1 extends Object {
2929
def /*MethodLocalTrait$1*/$init$(barParam$1: String): Unit = {
3030
()
@@ -54,7 +54,7 @@ package <empty> {
5454
T.this.MethodLocalObject$lzycompute$1(barParam$1, MethodLocalObject$module$1)
5555
else
5656
MethodLocalObject$module$1.elem.$asInstanceOf[T#MethodLocalObject$2.type]();
57-
final <artifact> private[this] def $anonfun$2(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try {
57+
final <artifact> private[this] def $anonfun$tryy$1(tryyParam$1: String, tryyLocal$1: runtime.ObjectRef): Unit = try {
5858
tryyLocal$1.elem = tryyParam$1
5959
} finally ()
6060
}

test/files/run/delambdafy_t6555.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ package <empty> {
66
()
77
};
88
private[this] val f: String => String = {
9-
final <artifact> def $anonfun(param: String): String = param;
10-
((param: String) => $anonfun(param))
9+
final <artifact> def $anonfun$f(param: String): String = param;
10+
((param: String) => $anonfun$f(param))
1111
};
1212
<stable> <accessor> def f(): String => String = Foo.this.f
1313
}

test/files/run/delambdafy_uncurry_byname_method.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ package <empty> {
77
};
88
def bar(x: () => String): String = x.apply();
99
def foo(): String = Foo.this.bar({
10-
final <artifact> def $anonfun(): String = "";
11-
(() => $anonfun())
10+
final <artifact> def $anonfun$foo(): String = "";
11+
(() => $anonfun$foo())
1212
})
1313
}
1414
}

test/files/run/delambdafy_uncurry_method.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ package <empty> {
77
};
88
def bar(): Unit = {
99
val f: Int => Int = {
10-
final <artifact> def $anonfun(x: Int): Int = x.+(1);
11-
((x: Int) => $anonfun(x))
10+
final <artifact> def $anonfun|(x: Int): Int = x.+(1);
11+
((x: Int) => $anonfun|(x))
1212
};
1313
()
1414
}

test/files/run/t9097.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ object Test extends StoreReporterDirectTest {
2828
assert(!storeReporter.hasErrors, message = filteredInfos map (_.msg) mkString "; ")
2929
val out = baos.toString("UTF-8")
3030
// was 2 before the fix, the two PackageDefs for a would both contain the ClassDef for the closure
31-
assert(out.lines.count(_ contains "def $anonfun$1(x$1: Int): String") == 1, out)
31+
assert(out.lines.count(_ contains "def $anonfun$hihi$1(x$1: Int): String") == 1, out)
3232
}
3333
}

test/junit/scala/tools/nsc/backend/jvm/IndySammyTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class IndySammyTest extends BytecodeTesting {
4343
val c = compileClass(s"class C { ${lamDef(from, to, body)}; ${appDef(arg)} }", allowMessage = allowMessage)
4444

4545
val applySig = getAsmMethod(funClass, "apply").desc
46-
val anonfun = getMethod(c, "C$$$anonfun$1")
46+
val anonfun = getMethod(c, "$anonfun$lam$1")
4747
val lamInsn = getInstructions(c, "lam").dropNonOp
4848
val applyInvoke = getMethod(c, "app")
4949

test/junit/scala/tools/nsc/backend/jvm/OptimizedBytecodeTest.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ class OptimizedBytecodeTest extends BytecodeTesting {
4343
val c = compileClass(code)
4444

4545
assertSameSummary(getMethod(c, "t"), List(
46-
LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "C$$$anonfun$1", IRETURN))
47-
assertSameSummary(getMethod(c, "C$$$anonfun$1"), List(LDC, "C$$$anonfun$2", IRETURN))
48-
assertSameSummary(getMethod(c, "C$$$anonfun$2"), List(-1 /*A*/, GOTO /*A*/))
46+
LDC, ASTORE, ALOAD /*0*/, ALOAD /*1*/, "$anonfun$t$1", IRETURN))
47+
assertSameSummary(getMethod(c, "$anonfun$t$1"), List(ALOAD, IFNONNULL, ACONST_NULL, ATHROW, -1, LDC, "$anonfun$t$2", IRETURN))
48+
assertSameSummary(getMethod(c, "$anonfun$t$2"), List(-1 /*A*/, GOTO /*A*/))
4949
}
5050

5151
@Test
@@ -295,9 +295,9 @@ class OptimizedBytecodeTest extends BytecodeTesting {
295295
|}
296296
""".stripMargin
297297
val c = compileClass(code, allowMessage = _.msg.contains("exception handler declared in the inlined method"))
298-
assertInvoke(getMethod(c, "f1a"), "C", "C$$$anonfun$1")
298+
assertInvoke(getMethod(c, "f1a"), "C", "$anonfun$f1a$1")
299299
assertInvoke(getMethod(c, "f1b"), "C", "wrapper1")
300-
assertInvoke(getMethod(c, "f2a"), "C", "C$$$anonfun$3")
300+
assertInvoke(getMethod(c, "f2a"), "C", "$anonfun$f2a$1")
301301
assertInvoke(getMethod(c, "f2b"), "C", "wrapper2")
302302
}
303303

@@ -331,7 +331,7 @@ class OptimizedBytecodeTest extends BytecodeTesting {
331331
|class Listt
332332
""".stripMargin
333333
val List(c, nil, nilMod, listt) = compileClasses(code)
334-
assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1")
334+
assertInvoke(getMethod(c, "t"), "C", "$anonfun$t$1")
335335
}
336336

337337
@Test
@@ -357,6 +357,6 @@ class OptimizedBytecodeTest extends BytecodeTesting {
357357
def optimiseEnablesNewOpt(): Unit = {
358358
val code = """class C { def t = (1 to 10) foreach println }"""
359359
val List(c) = readAsmClasses(newCompiler(extraArgs = "-optimise -deprecation").compileToBytes(code, allowMessage = _.msg.contains("is deprecated")))
360-
assertInvoke(getMethod(c, "t"), "C", "C$$$anonfun$1") // range-foreach inlined from classpath
360+
assertInvoke(getMethod(c, "t"), "C", "$anonfun$t$1") // range-foreach inlined from classpath
361361
}
362362
}

0 commit comments

Comments
 (0)