
scala.tools.nsc.backend.jvm.AsmUtils.scala Maven / Gradle / Ivy
/* NSC -- new Scala compiler
* Copyright 2005-2014 LAMP/EPFL
* @author Martin Odersky
*/
package scala.tools.nsc.backend.jvm
import scala.tools.asm.tree.{AbstractInsnNode, ClassNode, FieldNode, InsnList, MethodNode}
import java.io.{PrintWriter, StringWriter}
import java.util
import scala.tools.asm.util.{CheckClassAdapter, Textifier, TraceClassVisitor, TraceMethodVisitor}
import scala.tools.asm.{Attribute, ClassReader, ClassWriter}
import scala.collection.JavaConverters._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.tools.nsc.backend.jvm.analysis.InitialProducer
import scala.tools.nsc.backend.jvm.opt.InlineInfoAttributePrototype
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, Array[Attribute](InlineInfoAttributePrototype), 0)
node
}
def readClass(filename: String): ClassNode = readClass(classBytes(filename))
def classBytes(file: String): Array[Byte] = {
val f = new java.io.RandomAccessFile(file, "r")
val bytes = new Array[Byte](f.length.toInt)
f.read(bytes)
bytes
}
def classFromBytes(bytes: Array[Byte]): ClassNode = {
val node = new ClassNode()
new ClassReader(bytes).accept(node, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES)
node
}
// def main(args: Array[String]): Unit = println(textify(sortedClassRead(classBytes(args.head))))
def sortClassMembers(node: ClassNode): node.type = {
node.fields.sort(_.name compareTo _.name)
node.methods.sort(_.name compareTo _.name)
node
}
// drop ScalaSig annotation and class attributes
def zapScalaClassAttrs(node: ClassNode): node.type = {
if (node.visibleAnnotations != null)
node.visibleAnnotations = node.visibleAnnotations.asScala.filterNot(a => a == null || a.desc.contains("Lscala/reflect/ScalaSignature")).asJava
node.attrs = null
node
}
def main(args: Array[String]): Unit = args.par.foreach { classFileName =>
val node = zapScalaClassAttrs(sortClassMembers(classFromBytes(classBytes(classFileName))))
val pw = new PrintWriter(classFileName + ".asm")
val trace = new TraceClassVisitor(pw)
node.accept(trace)
pw.close()
}
/**
* 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 = insn match {
case _: InitialProducer =>
insn.toString
case _ =>
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)
/**
* Run ASM's CheckClassAdapter over a class. Returns None if no problem is found, otherwise
* Some(msg) with the verifier's error message.
*/
def checkClass(classNode: ClassNode, dumpNonErroneous: Boolean = false): Option[String] = {
val cw = new ClassWriter(ClassWriter.COMPUTE_MAXS)
classNode.accept(cw)
val sw = new StringWriter()
val pw = new PrintWriter(sw)
CheckClassAdapter.verify(new ClassReader(cw.toByteArray), dumpNonErroneous, pw)
val res = sw.toString
if (res.isEmpty) None else Some(res)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy