Skip to content

Commit

Permalink
Inline super calls, as they are statically resolved
Browse files Browse the repository at this point in the history
Ensures that mixin methods of `@inline` annotated concrete trait methods
inline the trait method.

Fixes scala/scala-dev#86
  • Loading branch information
lrytz committed Mar 23, 2016
1 parent 952da60 commit 548a5ba
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ object BytecodeUtils {

def isLoadOrStore(instruction: AbstractInsnNode): Boolean = isLoad(instruction) || isStore(instruction)

def isNonVirtualCall(instruction: AbstractInsnNode): Boolean = {
val op = instruction.getOpcode
op == INVOKESPECIAL || op == INVOKESTATIC
}

def isExecutable(instruction: AbstractInsnNode): Boolean = instruction.getOpcode >= 0

def isConstructor(methodNode: MethodNode): Boolean = {
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
(declarationClassNode, source) <- byteCodeRepository.classNodeAndSource(declarationClass): Either[OptimizerWarning, (ClassNode, Source)]
} yield {
val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
val CallsiteInfo(safeToInline, safeToRewrite, canInlineFromSource, annotatedInline, annotatedNoInline, samParamTypes, warning) = analyzeCallsite(method, declarationClassBType, call.owner, source)
val CallsiteInfo(safeToInline, safeToRewrite, canInlineFromSource, annotatedInline, annotatedNoInline, samParamTypes, warning) = analyzeCallsite(method, declarationClassBType, call, source)
Callee(
callee = method,
calleeDeclarationClass = declarationClassBType,
Expand Down Expand Up @@ -264,7 +264,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
/**
* Analyze a callsite and gather meta-data that can be used for inlining decisions.
*/
private def analyzeCallsite(calleeMethodNode: MethodNode, calleeDeclarationClassBType: ClassBType, receiverTypeInternalName: InternalName, calleeSource: Source): CallsiteInfo = {
private def analyzeCallsite(calleeMethodNode: MethodNode, calleeDeclarationClassBType: ClassBType, call: MethodInsnNode, calleeSource: Source): CallsiteInfo = {
val methodSignature = calleeMethodNode.name + calleeMethodNode.desc

try {
Expand All @@ -277,7 +277,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {

val isAbstract = BytecodeUtils.isAbstractMethod(calleeMethodNode)

val receiverType = classBTypeFromParsedClassfile(receiverTypeInternalName)
val receiverType = classBTypeFromParsedClassfile(call.owner)
// (1) A non-final method can be safe to inline if the receiver type is a final subclass. Example:
// class A { @inline def f = 1 }; object B extends A; B.f // can be inlined
//
Expand All @@ -295,6 +295,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
// TODO: type analysis can render more calls statically resolved. Example:
// new A.f // can be inlined, the receiver type is known to be exactly A.
val isStaticallyResolved: Boolean = {
isNonVirtualCall(call) || // SD-86: super calls (invokespecial) can be inlined
methodInlineInfo.effectivelyFinal ||
receiverType.info.orThrow.inlineInfo.isEffectivelyFinal // (1)
}
Expand Down
10 changes: 10 additions & 0 deletions test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1508,4 +1508,14 @@ class InlinerTest extends ClearAfterClass {
val List(a, b) = compileClassesSeparately(List(codeA, codeB), extraArgs = "-Yopt:l:project -Yopt-warnings")
assertInvoke(getSingleMethod(b, "t"), "A", "f")
}

@Test
def sd86(): Unit = {
val code =
"""trait T { @inline def f = 1 } // note that f is not final
|class C extends T
""".stripMargin
val List(c, t) = compile(code, allowMessage = _ => true)
assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
}
}

0 comments on commit 548a5ba

Please sign in to comment.