diff options
author | Lukas Rytz <lukas.rytz@gmail.com> | 2014-05-10 09:07:36 +0200 |
---|---|---|
committer | Lukas Rytz <lukas.rytz@gmail.com> | 2014-05-13 15:17:17 +0200 |
commit | 9e1b464d44d2402211b905d6d89cf4004090fe43 (patch) | |
tree | 2f140ce75390ba3e5c7fd519d15b76438110cf5a | |
parent | ea166087ce3fe2731a8b0d767cbbd4c5e5e648c1 (diff) | |
download | scala-9e1b464d44d2402211b905d6d89cf4004090fe43.tar.gz scala-9e1b464d44d2402211b905d6d89cf4004090fe43.tar.bz2 scala-9e1b464d44d2402211b905d6d89cf4004090fe43.zip |
Allow tracing methods and classes in GenBCode
5 files changed, 75 insertions, 2 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala new file mode 100644 index 0000000000..856f85d9e3 --- /dev/null +++ b/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala @@ -0,0 +1,53 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2014 LAMP/EPFL + * @author Martin Odersky + */ + +package scala.tools.nsc.backend.jvm + +import scala.tools.asm.tree.{ClassNode, MethodNode} +import java.io.PrintWriter +import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier} + +object AsmUtils { + + /** + * Print the bytecode of methods generated by GenBCode to the standard output. Only methods + * whose name contains `traceMethodPattern` are traced. + */ + final val traceMethodEnabled = false + final val traceMethodPattern = "" + + /** + * Print the bytecode of classes generated by GenBCode to the standard output. + */ + final val traceClassEnabled = false + final val traceClassPattern = "" + + /** + * Print the bytedcode of classes as they are serialized by the ASM library. The serialization + * performed by `asm.ClassWriter` can change the code generated by GenBCode. For example, it + * introduces stack map frames, it computes the maximal stack sizes, and it replaces dead + * code by NOPs (see also https://github.com/scala/scala/pull/3726#issuecomment-42861780). + */ + final val traceSerializedClassEnabled = false + final val traceSerializedClassPattern = "" + + def traceMethod(mnode: MethodNode): Unit = { + println(s"Bytecode for method ${mnode.name}") + val p = new Textifier + val tracer = new TraceMethodVisitor(p) + mnode.accept(tracer) + val w = new PrintWriter(System.out) + p.print(w) + w.flush() + } + + def traceClass(cnode: ClassNode): Unit = { + println(s"Bytecode for class ${cnode.name}") + val w = new PrintWriter(System.out) + cnode.accept(new TraceClassVisitor(w)) + w.flush() + } + +} diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index 92ebe5027a..3d1b646069 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -808,7 +808,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { emit(asm.Opcodes.ATHROW) // ICode enters here into enterIgnoreMode, we'll rely instead on DCE at ClassNode level. } else if (from.isNullType) { bc drop from - mnode.visitInsn(asm.Opcodes.ACONST_NULL) + emit(asm.Opcodes.ACONST_NULL) } else (from, to) match { case (BYTE, LONG) | (SHORT, LONG) | (CHAR, LONG) | (INT, LONG) => bc.emitT2T(INT, LONG) diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala index 360ce58ecc..dae53bc0e5 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeSkelBuilder.scala @@ -14,6 +14,8 @@ import scala.tools.nsc.symtab._ import scala.annotation.switch import scala.tools.asm +import scala.tools.asm.util.{TraceMethodVisitor, ASMifier} +import java.io.PrintWriter /* * @@ -117,6 +119,9 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { gen(cd.impl) + if (AsmUtils.traceClassEnabled && cnode.name.contains(AsmUtils.traceClassPattern)) + AsmUtils.traceClass(cnode) + assert(cd.symbol == claszSymbol, "Someone messed up BCodePhase.claszSymbol during genPlainClass().") } // end of method genPlainClass() @@ -639,6 +644,10 @@ abstract class BCodeSkelBuilder extends BCodeHelpers { // Note we don't invoke visitMax, thus there are no FrameNode among mnode.instructions. // The only non-instruction nodes to be found are LabelNode and LineNumberNode. } + + if (AsmUtils.traceMethodEnabled && mnode.name.contains(AsmUtils.traceMethodPattern)) + AsmUtils.traceMethod(mnode) + mnode = null } // end of method genDefDef() diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala index 8e6c09213f..1d29fdee10 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BytecodeWriters.scala @@ -1,6 +1,6 @@ /* NSC -- new Scala compiler * Copyright 2005-2013 LAMP/EPFL - * @author Paul Phillips + * @author Martin Odersky */ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala index 193100474c..61cf76f524 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenBCode.scala @@ -243,6 +243,17 @@ abstract class GenBCode extends BCodeSyncAndTry { val plainC = SubItem3(plain.name, getByteArray(plain)) val beanC = if (bean == null) null else SubItem3(bean.name, getByteArray(bean)) + if (AsmUtils.traceSerializedClassEnabled && plain.name.contains(AsmUtils.traceSerializedClassPattern)) { + def readClass(bytes: Array[Byte]): asm.tree.ClassNode = { + val node = new asm.tree.ClassNode() + new asm.ClassReader(bytes).accept(node, 0) + node + } + if (mirrorC != null) AsmUtils.traceClass(readClass(mirrorC.jclassBytes)) + AsmUtils.traceClass(readClass(plainC.jclassBytes)) + if (beanC != null) AsmUtils.traceClass(readClass(beanC.jclassBytes)) + } + q3 add Item3(arrivalPos, mirrorC, plainC, beanC, outFolder) } |