diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-03-11 10:39:40 -0700 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-03-11 15:18:23 -0700 |
commit | 2d88143f37144f3db5a1d1d27806518bea13ba47 (patch) | |
tree | 463fea2543fd12ac898b1c7d313b74543960327a /src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala | |
parent | f8731c5b17274d68de3469e34727e24a937ffc84 (diff) | |
download | scala-2d88143f37144f3db5a1d1d27806518bea13ba47.tar.gz scala-2d88143f37144f3db5a1d1d27806518bea13ba47.tar.bz2 scala-2d88143f37144f3db5a1d1d27806518bea13ba47.zip |
Ensure to re-write only trait method calls of actual trait methods
The inliner would incorrectly treat trait field accessors like
ordinary trait member methods and try to re-write invocations to the
corresponding static method in the implementation class. This rewrite
usually failed because no method was found in the impl class.
However, for lazy val fields, there exists a member in the impl class
with the same name, and the rewrite was performed. The result was that
every field access would execute the lazy initializer instead of
reading the field.
This commit checks the traitMethodWithStaticImplementation field of
the ScalaInlineInfo classfile attribute and puts an explicit
`safeToRewrite` flag to each call site in the call graph. This cleans
up the code in the inliner that deals with rewriting trait callsites.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala | 30 |
1 files changed, 10 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala index 7ce98ecff1..0f4c7d5287 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala @@ -71,7 +71,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { */ def selectCallsitesForInlining: List[Callsite] = { callsites.valuesIterator.filter({ - case callsite @ Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, annotatedInline, _, warning)), _, _, pos) => + case callsite @ Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, annotatedInline, _, warning)), _, _, pos) => val res = doInlineCallsite(callsite) if (!res) { @@ -80,10 +80,10 @@ class Inliner[BT <: BTypes](val btypes: BT) { // reason is, for example, mixed compilation (which has a separate -Yopt-warning flag). def initMsg = s"${BackendReporting.methodSignature(calleeDeclClass.internalName, callee)} is annotated @inline but cannot be inlined" def warnMsg = warning.map(" Possible reason:\n" + _).getOrElse("") - if (!safeToInline) - backendReporting.inlinerWarning(pos, s"$initMsg: the method is not final and may be overridden." + warnMsg) - else if (doRewriteTraitCallsite(callsite) && isAbstractMethod(callee)) + if (doRewriteTraitCallsite(callsite)) backendReporting.inlinerWarning(pos, s"$initMsg: the trait method call could not be rewritten to the static implementation method." + warnMsg) + else if (!safeToInline) + backendReporting.inlinerWarning(pos, s"$initMsg: the method is not final and may be overridden." + warnMsg) else backendReporting.inlinerWarning(pos, s"$initMsg." + warnMsg) } else if (warning.isDefined && warning.get.emitWarning(warnSettings)) { @@ -105,13 +105,8 @@ class Inliner[BT <: BTypes](val btypes: BT) { * The current inlining heuristics are simple: inline calls to methods annotated @inline. */ def doInlineCallsite(callsite: Callsite): Boolean = callsite match { - case Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, annotatedInline, _, warning)), _, _, pos) => - // Usually, safeToInline implies that the callee is not abstract. - // But for final trait methods, the callee is abstract: "trait T { @inline final def f = 1}". - // A callsite (t: T).f is `safeToInline`, but the callee is the abstract method in the interface. - // We try to rewrite these calls to the static impl method, but that may not always succeed, - // in which case we cannot inline the call. - annotatedInline && safeToInline && !isAbstractMethod(callee) + case Callsite(_, _, _, Right(Callee(callee, calleeDeclClass, safeToInline, _, annotatedInline, _, warning)), _, _, pos) => + annotatedInline && safeToInline case _ => false } @@ -127,13 +122,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { * True for statically resolved trait callsites that should be rewritten to the static implementation method. */ def doRewriteTraitCallsite(callsite: Callsite) = callsite.callee match { - case Right(Callee(callee, calleeDeclarationClass, true, annotatedInline, annotatedNoInline, infoWarning)) if isAbstractMethod(callee) => - // The pattern matches abstract methods that are `safeToInline`. This can only match the interface method of a final, concrete - // trait method. An abstract method (in a trait or abstract class) is never `safeToInline` (abstract methods cannot be final). - // See also comment in `doInlineCallsite` - for (i <- calleeDeclarationClass.isInterface) assert(i, s"expected interface call (final trait method) when inlining abstract method: $callsite") - true - + case Right(Callee(callee, calleeDeclarationClass, safeToInline, true, annotatedInline, annotatedNoInline, infoWarning)) => true case _ => false } @@ -146,7 +135,7 @@ class Inliner[BT <: BTypes](val btypes: BT) { */ def rewriteFinalTraitMethodInvocation(callsite: Callsite): Unit = { if (doRewriteTraitCallsite(callsite)) { - val Right(Callee(callee, calleeDeclarationClass, safeToInline, annotatedInline, annotatedNoInline, infoWarning)) = callsite.callee + val Right(Callee(callee, calleeDeclarationClass, _, _, annotatedInline, annotatedNoInline, infoWarning)) = callsite.callee val traitMethodArgumentTypes = asm.Type.getArgumentTypes(callee.desc) @@ -198,7 +187,8 @@ class Inliner[BT <: BTypes](val btypes: BT) { callee = Right(Callee( callee = implClassMethod, calleeDeclarationClass = implClassBType, - safeToInline = safeToInline, + safeToInline = true, + safeToRewrite = false, annotatedInline = annotatedInline, annotatedNoInline = annotatedNoInline, calleeInfoWarning = infoWarning)), |