summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@typesafe.com>2016-03-30 11:07:37 +0200
committerLukas Rytz <lukas.rytz@typesafe.com>2016-03-30 11:07:37 +0200
commitecc89449eebda0f6464e1dcc1e61bbdc46bdab3f (patch)
treeee0b695eac42ac90fa572e84fe36adc908bd77b1 /src/compiler
parente5bbc98f780070326498d55bb0bdcde9bb6a746b (diff)
parente483fe26825501c175b701a662160dd0e54b035e (diff)
downloadscala-ecc89449eebda0f6464e1dcc1e61bbdc46bdab3f.tar.gz
scala-ecc89449eebda0f6464e1dcc1e61bbdc46bdab3f.tar.bz2
scala-ecc89449eebda0f6464e1dcc1e61bbdc46bdab3f.zip
Merge pull request #5058 from lrytz/newTraitsInliner
Inline super calls, as they are statically resolved
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala5
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala7
2 files changed, 9 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
index 9a90c53d3e..f48f60a438 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/BytecodeUtils.scala
@@ -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 = {
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
index 6dd74bad84..3267b9b5df 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/CallGraph.scala
@@ -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,
@@ -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 {
@@ -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
//
@@ -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)
}