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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
/* NSC -- new Scala compiler
* Copyright 2005-2012 LAMP/EPFL
* @author Paul Phillips
*/
package scala.tools
package util
import java.lang.reflect.{ GenericSignatureFormatError, Method, Constructor }
import java.lang.{ ClassLoader => JavaClassLoader }
import scala.tools.nsc.util.ScalaClassLoader
import java.io.{ InputStream, PrintWriter, ByteArrayInputStream, FileNotFoundException }
import scala.tools.nsc.io.File
import Javap._
import scala.language.reflectiveCalls
trait Javap {
def loader: ScalaClassLoader
def printWriter: PrintWriter
def apply(args: Seq[String]): List[JpResult]
def tryFile(path: String): Option[Array[Byte]]
def tryClass(path: String): Array[Byte]
}
object NoJavap extends Javap {
def loader: ScalaClassLoader = getClass.getClassLoader
def printWriter: PrintWriter = new PrintWriter(System.err, true)
def apply(args: Seq[String]): List[JpResult] = Nil
def tryFile(path: String): Option[Array[Byte]] = None
def tryClass(path: String): Array[Byte] = Array()
}
class JavapClass(
val loader: ScalaClassLoader = ScalaClassLoader.appLoader,
val printWriter: PrintWriter = new PrintWriter(System.out, true)
) extends Javap {
lazy val parser = new JpOptions
val EnvClass = loader.tryToInitializeClass[FakeEnvironment](Env).orNull
val PrinterClass = loader.tryToInitializeClass[FakePrinter](Printer).orNull
private def failed = (EnvClass eq null) || (PrinterClass eq null)
val PrinterCtr = (
if (failed) null
else PrinterClass.getConstructor(classOf[InputStream], classOf[PrintWriter], EnvClass)
)
def findBytes(path: String): Array[Byte] =
tryFile(path) getOrElse tryClass(path)
def apply(args: Seq[String]): List[JpResult] = {
if (failed) Nil
else args.toList filterNot (_ startsWith "-") map { path =>
val bytes = findBytes(path)
if (bytes.isEmpty) new JpError("Could not find class bytes for '%s'".format(path))
else new JpSuccess(newPrinter(new ByteArrayInputStream(bytes), newEnv(args)))
}
}
def newPrinter(in: InputStream, env: FakeEnvironment): FakePrinter =
if (failed) null
else PrinterCtr.newInstance(in, printWriter, env)
def newEnv(opts: Seq[String]): FakeEnvironment = {
lazy val env: FakeEnvironment = EnvClass.newInstance()
if (failed) null
else parser(opts) foreach { case (name, value) =>
val field = EnvClass getDeclaredField name
field setAccessible true
field.set(env, value.asInstanceOf[AnyRef])
}
env
}
/** Assume the string is a path and try to find the classfile
* it represents.
*/
def tryFile(path: String): Option[Array[Byte]] = {
val file = File(
if (path.endsWith(".class")) path
else path.replace('.', '/') + ".class"
)
if (!file.exists) None
else try Some(file.toByteArray) catch { case x: Exception => None }
}
/** Assume the string is a fully qualified class name and try to
* find the class object it represents.
*/
def tryClass(path: String): Array[Byte] = {
val extName = (
if (path endsWith ".class") (path dropRight 6).replace('/', '.')
else path
)
loader.classBytes(extName)
}
}
object Javap {
val Env = "sun.tools.javap.JavapEnvironment"
val Printer = "sun.tools.javap.JavapPrinter"
def isAvailable(cl: ScalaClassLoader = ScalaClassLoader.appLoader) =
cl.tryToInitializeClass[AnyRef](Env).isDefined
// "documentation"
type FakeEnvironment = AnyRef
type FakePrinter = AnyRef
def apply(path: String): Unit = apply(Seq(path))
def apply(args: Seq[String]): Unit = new JavapClass() apply args foreach (_.show())
sealed trait JpResult {
type ResultType
def isError: Boolean
def value: ResultType
def show(): Unit
// todo
// def header(): String
// def fields(): List[String]
// def methods(): List[String]
// def signatures(): List[String]
}
class JpError(msg: String) extends JpResult {
type ResultType = String
def isError = true
def value = msg
def show() = println(msg)
}
class JpSuccess(val value: AnyRef) extends JpResult {
type ResultType = AnyRef
def isError = false
def show() = value.asInstanceOf[{ def print(): Unit }].print()
}
class JpOptions {
private object Access {
final val PRIVATE = 0
final val PROTECTED = 1
final val PACKAGE = 2
final val PUBLIC = 3
}
private val envActionMap: Map[String, (String, Any)] = {
val map = Map(
"-l" -> (("showLineAndLocal", true)),
"-c" -> (("showDisassembled", true)),
"-s" -> (("showInternalSigs", true)),
"-verbose" -> (("showVerbose", true)),
"-private" -> (("showAccess", Access.PRIVATE)),
"-package" -> (("showAccess", Access.PACKAGE)),
"-protected" -> (("showAccess", Access.PROTECTED)),
"-public" -> (("showAccess", Access.PUBLIC)),
"-all" -> (("showallAttr", true))
)
map ++ List(
"-v" -> map("-verbose"),
"-p" -> map("-private")
)
}
def apply(opts: Seq[String]): Seq[(String, Any)] = {
opts flatMap { opt =>
envActionMap get opt match {
case Some(pair) => List(pair)
case _ =>
val charOpts = opt.tail.toSeq map ("-" + _)
if (charOpts forall (envActionMap contains _))
charOpts map envActionMap
else Nil
}
}
}
}
}
|