diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2015-03-11 12:09:21 -0700 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2015-03-11 13:47:07 -0700 |
commit | f8bb3d5289e5eb84ccd94386e5c3df1bdf8b91bc (patch) | |
tree | d7745fc7de76b699304e1ddac255e531134400ff /src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala | |
parent | 027e97981d9b6a3783e9ab247cc898017b3de821 (diff) | |
download | scala-f8bb3d5289e5eb84ccd94386e5c3df1bdf8b91bc.tar.gz scala-f8bb3d5289e5eb84ccd94386e5c3df1bdf8b91bc.tar.bz2 scala-f8bb3d5289e5eb84ccd94386e5c3df1bdf8b91bc.zip |
Inline final methods defined in traits
In order to inline a final trait method, callsites of such methods are
first re-written from interface calls to static calls of the trait's
implementation class. Then inlining proceeds as ususal.
One problem that came up during development was that mixin methods are
added to class symbols only for classes being compiled, but not for
others. In order to inline a mixin method, we need the InlineInfo,
which so far was built using the class (and method) symbols. So we had
a problem with separate compilation.
Looking up the symbol from a given classfile name was already known to
be brittle (it's also one of the weak points of the current inliner),
so we changed the strategy. Now the InlineInfo for every class is
encoded in a new classfile attribute.
This classfile attribute is relatively small, because all strings it
references (class internal names, method names, method descriptors)
would exist anyway in the constant pool, so it just adds a few
references.
When building the InlineInfo for a class symbol, we only look at the
symbol properties for symbols being compiled in the current run. For
unpickled symbols, we build the InlineInfo by reading the classfile
attribute.
This change also adds delambdafy:method classes to currentRun.symSource.
Otherwise, currentRun.compiles(lambdaClass) is false.
Diffstat (limited to 'src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala index ea4dd0c032..fb58f1b189 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/opt/ByteCodeRepository.scala @@ -10,6 +10,7 @@ package opt import scala.tools.asm import asm.tree._ import scala.collection.convert.decorateAsScala._ +import scala.tools.asm.Attribute import scala.tools.nsc.io.AbstractFile import scala.tools.nsc.util.ClassFileLookup import OptimizerReporting._ @@ -64,6 +65,7 @@ class ByteCodeRepository(val classPath: ClassFileLookup[AbstractFile], val class */ def methodNode(ownerInternalNameOrArrayDescriptor: String, name: String, descriptor: String): Option[(MethodNode, InternalName)] = { // In a MethodInsnNode, the `owner` field may be an array descriptor, for exmple when invoking `clone`. + // We don't inline array methods (they are native anyway), so just return None. if (ownerInternalNameOrArrayDescriptor.charAt(0) == '[') None else { classNode(ownerInternalNameOrArrayDescriptor).flatMap(c => @@ -80,9 +82,13 @@ class ByteCodeRepository(val classPath: ClassFileLookup[AbstractFile], val class classPath.findClassFile(fullName) map { classFile => val classNode = new asm.tree.ClassNode() val classReader = new asm.ClassReader(classFile.toByteArray) + + // Passing the InlineInfoAttributePrototype makes the ClassReader invoke the specific `read` + // method of the InlineInfoAttribute class, instead of putting the byte array into a generic + // Attribute. // We don't need frames when inlining, but we want to keep the local variable table, so we // don't use SKIP_DEBUG. - classReader.accept(classNode, asm.ClassReader.SKIP_FRAMES) + classReader.accept(classNode, Array[Attribute](InlineInfoAttributePrototype), asm.ClassReader.SKIP_FRAMES) // SKIP_FRAMES leaves line number nodes. Remove them because they are not correct after // inlining. // TODO: we need to remove them also for classes that are not parsed from classfiles, why not simplify and do it once when inlining? |