summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorLukas Rytz <lukas.rytz@gmail.com>2015-03-12 15:32:46 -0700
committerLukas Rytz <lukas.rytz@gmail.com>2015-03-12 16:34:21 -0700
commitc2ab768287cc02b5e01342ac993d6c2b6e7ee2aa (patch)
tree8f6eb1d2132585be7f869b488e195149b03bd461 /src/compiler
parentba325127141e70e3464be80fddc699e23b638a3d (diff)
downloadscala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.tar.gz
scala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.tar.bz2
scala-c2ab768287cc02b5e01342ac993d6c2b6e7ee2aa.zip
Don't inline methods containing super calls into other classes
Method bodies that contain a super call cannot be inlined into other classes. The same goes for methods containing calls to private methods, but that was already ensured before by accessibility checks. The last case of `invokespecial` instructions is constructor calls. Those can be safely moved into different classes (as long as the constructor is accessible at the new location). Note that scalac never emits methods / constructors as private in bytecode.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala18
1 files changed, 15 insertions, 3 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 0f4c7d5287..e14e57d3ab 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/Inliner.scala
@@ -480,7 +480,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
Some(MethodWithHandlerCalledOnNonEmptyStack(
calleeDeclarationClass.internalName, callee.name, callee.desc,
callsiteClass.internalName, callsiteMethod.name, callsiteMethod.desc))
- } else findIllegalAccess(callee.instructions, callsiteClass) map {
+ } else findIllegalAccess(callee.instructions, calleeDeclarationClass, callsiteClass) map {
case (illegalAccessIns, None) =>
IllegalAccessInstruction(
calleeDeclarationClass.internalName, callee.name, callee.desc,
@@ -500,7 +500,7 @@ class Inliner[BT <: BTypes](val btypes: BT) {
* If validity of some instruction could not be checked because an error occurred, the instruction
* is returned together with a warning message that describes the problem.
*/
- def findIllegalAccess(instructions: InsnList, destinationClass: ClassBType): Option[(AbstractInsnNode, Option[OptimizerWarning])] = {
+ def findIllegalAccess(instructions: InsnList, calleeDeclarationClass: ClassBType, destinationClass: ClassBType): Option[(AbstractInsnNode, Option[OptimizerWarning])] = {
/**
* Check if a type is accessible to some class, as defined in JVMS 5.4.4.
@@ -597,11 +597,23 @@ class Inliner[BT <: BTypes](val btypes: BT) {
case mi: MethodInsnNode =>
if (mi.owner.charAt(0) == '[') Right(true) // array methods are accessible
else {
+ def canInlineCall(opcode: Int, methodFlags: Int, methodDeclClass: ClassBType, methodRefClass: ClassBType): Either[OptimizerWarning, Boolean] = {
+ opcode match {
+ case INVOKESPECIAL if mi.name != GenBCode.INSTANCE_CONSTRUCTOR_NAME =>
+ // invokespecial is used for private method calls, super calls and instance constructor calls.
+ // private method and super calls can only be inlined into the same class.
+ Right(destinationClass == calleeDeclarationClass)
+
+ case _ => // INVOKEVIRTUAL, INVOKESTATIC, INVOKEINTERFACE and INVOKESPECIAL of constructors
+ memberIsAccessible(methodFlags, methodDeclClass, methodRefClass)
+ }
+ }
+
val methodRefClass = classBTypeFromParsedClassfile(mi.owner)
for {
(methodNode, methodDeclClassNode) <- byteCodeRepository.methodNode(methodRefClass.internalName, mi.name, mi.desc): Either[OptimizerWarning, (MethodNode, InternalName)]
methodDeclClass = classBTypeFromParsedClassfile(methodDeclClassNode)
- res <- memberIsAccessible(methodNode.access, methodDeclClass, methodRefClass)
+ res <- canInlineCall(mi.getOpcode, methodNode.access, methodDeclClass, methodRefClass)
} yield {
res
}