Skip to content

Commit 9656570

Browse files
committed
Inline super calls, as they are statically resolved
Ensures that mixin methods of `@inline` annotated concrete trait methods inline the trait method. Fixes scala/scala-dev#86
1 parent ce8ce43 commit 9656570

File tree

3 files changed

+19
-3
lines changed

3 files changed

+19
-3
lines changed

src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ object BytecodeUtils {
8888

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

91+
def isNonVirtualCall(instruction: AbstractInsnNode): Boolean = {
92+
val op = instruction.getOpcode
93+
op == INVOKESPECIAL || op == INVOKESTATIC
94+
}
95+
9196
def isExecutable(instruction: AbstractInsnNode): Boolean = instruction.getOpcode >= 0
9297

9398
def isConstructor(methodNode: MethodNode): Boolean = {

src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
132132
(declarationClassNode, source) <- byteCodeRepository.classNodeAndSource(declarationClass): Either[OptimizerWarning, (ClassNode, Source)]
133133
} yield {
134134
val declarationClassBType = classBTypeFromClassNode(declarationClassNode)
135-
val CallsiteInfo(safeToInline, safeToRewrite, canInlineFromSource, annotatedInline, annotatedNoInline, samParamTypes, warning) = analyzeCallsite(method, declarationClassBType, call.owner, source)
135+
val CallsiteInfo(safeToInline, safeToRewrite, canInlineFromSource, annotatedInline, annotatedNoInline, samParamTypes, warning) = analyzeCallsite(method, declarationClassBType, call, source)
136136
Callee(
137137
callee = method,
138138
calleeDeclarationClass = declarationClassBType,
@@ -264,7 +264,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
264264
/**
265265
* Analyze a callsite and gather meta-data that can be used for inlining decisions.
266266
*/
267-
private def analyzeCallsite(calleeMethodNode: MethodNode, calleeDeclarationClassBType: ClassBType, receiverTypeInternalName: InternalName, calleeSource: Source): CallsiteInfo = {
267+
private def analyzeCallsite(calleeMethodNode: MethodNode, calleeDeclarationClassBType: ClassBType, call: MethodInsnNode, calleeSource: Source): CallsiteInfo = {
268268
val methodSignature = calleeMethodNode.name + calleeMethodNode.desc
269269

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

278278
val isAbstract = BytecodeUtils.isAbstractMethod(calleeMethodNode)
279279

280-
val receiverType = classBTypeFromParsedClassfile(receiverTypeInternalName)
280+
val receiverType = classBTypeFromParsedClassfile(call.owner)
281281
// (1) A non-final method can be safe to inline if the receiver type is a final subclass. Example:
282282
// class A { @inline def f = 1 }; object B extends A; B.f // can be inlined
283283
//
@@ -295,6 +295,7 @@ class CallGraph[BT <: BTypes](val btypes: BT) {
295295
// TODO: type analysis can render more calls statically resolved. Example:
296296
// new A.f // can be inlined, the receiver type is known to be exactly A.
297297
val isStaticallyResolved: Boolean = {
298+
isNonVirtualCall(call) || // SD-86: super calls (invokespecial) can be inlined
298299
methodInlineInfo.effectivelyFinal ||
299300
receiverType.info.orThrow.inlineInfo.isEffectivelyFinal // (1)
300301
}

test/junit/scala/tools/nsc/backend/jvm/opt/InlinerTest.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,4 +1502,14 @@ class InlinerTest extends ClearAfterClass {
15021502
val List(a, b) = compileClassesSeparately(List(codeA, codeB), extraArgs = "-Yopt:l:project -Yopt-warnings")
15031503
assertInvoke(getSingleMethod(b, "t"), "A", "f")
15041504
}
1505+
1506+
@Test
1507+
def sd86(): Unit = {
1508+
val code =
1509+
"""trait T { @inline def f = 1 } // note that f is not final
1510+
|class C extends T
1511+
""".stripMargin
1512+
val List(c, t) = compile(code, allowMessage = _ => true)
1513+
assertSameSummary(getSingleMethod(c, "f"), List(ICONST_1, IRETURN))
1514+
}
15051515
}

0 commit comments

Comments
 (0)