summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/jvm/AsmUtils.scala
blob: 75aa0fc98469e7217c9d2c3f3b57827a09329282 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/* NSC -- new Scala compiler
 * Copyright 2005-2014 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala.tools.nsc.backend.jvm

import scala.tools.asm.tree.{InsnList, AbstractInsnNode, ClassNode, MethodNode}
import java.io.{StringWriter, PrintWriter}
import scala.tools.asm.util.{TraceClassVisitor, TraceMethodVisitor, Textifier}
import scala.tools.asm.ClassReader
import scala.collection.convert.decorateAsScala._

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}")
    println(textify(mnode))
  }

  def traceClass(cnode: ClassNode): Unit = {
    println(s"Bytecode for class ${cnode.name}")
    println(textify(cnode))
  }

  def traceClass(bytes: Array[Byte]): Unit = traceClass(readClass(bytes))

  def readClass(bytes: Array[Byte]): ClassNode = {
    val node = new ClassNode()
    new ClassReader(bytes).accept(node, 0)
    node
  }

  /**
   * Returns a human-readable representation of the cnode ClassNode.
   */
  def textify(cnode: ClassNode): String = {
    val trace = new TraceClassVisitor(new PrintWriter(new StringWriter))
    cnode.accept(trace)
    val sw = new StringWriter
    val pw = new PrintWriter(sw)
    trace.p.print(pw)
    sw.toString
  }

  /**
   * Returns a human-readable representation of the code in the mnode MethodNode.
   */
  def textify(mnode: MethodNode): String = {
    val trace = new TraceClassVisitor(new PrintWriter(new StringWriter))
    mnode.accept(trace)
    val sw = new StringWriter
    val pw = new PrintWriter(sw)
    trace.p.print(pw)
    sw.toString
  }

  /**
   * Returns a human-readable representation of the given instruction.
   */
  def textify(insn: AbstractInsnNode): String = {
    val trace = new TraceMethodVisitor(new Textifier)
    insn.accept(trace)
    val sw = new StringWriter
    val pw = new PrintWriter(sw)
    trace.p.print(pw)
    sw.toString.trim
  }

  /**
   * Returns a human-readable representation of the given instruction sequence.
   */
  def textify(insns: Iterator[AbstractInsnNode]): String = {
    val trace = new TraceMethodVisitor(new Textifier)
    insns.foreach(_.accept(trace))
    val sw: StringWriter = new StringWriter
    val pw: PrintWriter = new PrintWriter(sw)
    trace.p.print(pw)
    sw.toString.trim
  }

  /**
   * Returns a human-readable representation of the given instruction sequence.
   */
  def textify(insns: InsnList): String = textify(insns.iterator().asScala)
}