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
|
/* ___ ____ ___ __ ___ ___
** / _// __// _ | / / / _ | / _ \ Scala classfile decoder
** __\ \/ /__/ __ |/ /__/ __ |/ ___/ (c) 2003-2013, LAMP/EPFL
** /____/\___/_/ |_/____/_/ |_/_/
**
*/
package scala.tools.scalap
class Classfile(in: ByteArrayReader) {
import Classfiles._
type UTF8 = Pool#UTF8
assert(in.nextInt == JAVA_MAGIC)
val minorVersion = in.nextChar
val majorVersion = in.nextChar
val pool = new Pool()
val flags = in.nextChar
val classname = in.nextChar
val superclass = in.nextChar
val interfaces = readInterfaces
val fields = readMembers(true)
val methods = readMembers(false)
val attribs = readAttribs
def scalaSigAttribute = attribs find (_.toString == Main.SCALA_SIG)
def readAttribs = {
val n = in.nextChar
var attribs: List[Attribute] = Nil
var i = 0
while (i < n) {
attribs = Attribute(in.nextChar.toInt, in.nextBytes(in.nextInt)) :: attribs
i = i + 1
}
attribs
}
def readMembers(field: Boolean) = {
val n = in.nextChar
var members: List[Member] = Nil
var i = 0
while (i < n) {
members = Member(field, in.nextChar.toInt, in.nextChar.toInt, in.nextChar.toInt, readAttribs) :: members
i = i + 1
}
members
}
def readInterfaces = {
val n = in.nextChar
var intfs: List[Int] = Nil
var i = 0
while (i < n) {
intfs = in.nextChar.toInt :: intfs
i = i + 1
}
intfs
}
class Pool() {
sealed abstract class PoolEntry(val tag: Int) {
def typeString = constantTagToString(tag)
}
case class UTF8(str: String) extends PoolEntry(CONSTANT_UTF8) { override def toString = "\"" + str + "\"" }
case class ClassRef(classId: Int) extends PoolEntry(CONSTANT_CLASS) { override def toString = "Class(%s)".format(entries(classId)) }
case class FieldRef(classId: Int, memberId: Int) extends PoolEntry(CONSTANT_FIELDREF)
case class MethodRef(classId: Int, memberId: Int) extends PoolEntry(CONSTANT_METHODREF) {
// //Method java/lang/Object."<init>":()V
override def toString() = "Method %s.\"%s\"".format(entries(classId), entries(memberId))
}
case class IntfMethodRef(classId: Int, memberId: Int) extends PoolEntry(CONSTANT_INTFMETHODREF)
case class StringConst(strId: Int) extends PoolEntry(CONSTANT_STRING)
case class IntegerConst(x: Int) extends PoolEntry(CONSTANT_INTEGER)
case class FloatConst(x: Float) extends PoolEntry(CONSTANT_FLOAT)
case class LongConst(x: Long) extends PoolEntry(CONSTANT_LONG)
case class DoubleConst(x: Double) extends PoolEntry(CONSTANT_DOUBLE)
case class NameAndType(nameId: Int, typeId: Int) extends PoolEntry(CONSTANT_NAMEANDTYPE)
case object Empty extends PoolEntry(0) { }
val entries = {
val pool = new Array[PoolEntry](in.nextChar.toInt)
var i = 1
while (i < pool.length) {
val tag = in.nextByte
// Double sized entry
if (tag == CONSTANT_LONG || tag == CONSTANT_DOUBLE) {
pool(i) = if (tag == CONSTANT_LONG) LongConst(in.nextLong) else DoubleConst(in.nextDouble)
i = i + 1
pool(i) = Empty
}
else pool(i) = tag match {
case CONSTANT_UTF8 => UTF8(in.nextUTF8(in.nextChar.toInt))
case CONSTANT_UNICODE => in.skip(in.nextChar) ; Empty
case CONSTANT_CLASS => ClassRef(in.nextChar)
case CONSTANT_STRING => StringConst(in.nextChar)
case CONSTANT_FIELDREF => FieldRef(in.nextChar, in.nextChar)
case CONSTANT_METHODREF => MethodRef(in.nextChar, in.nextChar)
case CONSTANT_INTFMETHODREF => IntfMethodRef(in.nextChar, in.nextChar)
case CONSTANT_NAMEANDTYPE => NameAndType(in.nextChar, in.nextChar)
case CONSTANT_INTEGER => IntegerConst(in.nextInt)
case CONSTANT_FLOAT => FloatConst(in.nextFloat)
}
i += 1
}
pool
}
lazy val length = entries.length
def apply(x: Int) = entries(x)
def stringOf(x: Int) = apply(x).toString
override def toString = (
for ((x, i) <- entries.zipWithIndex ; if x != null) yield
"const #%d = %s\t%s\n".format(i + 1, x.typeString, x)
).mkString
}
/** **/
case class Member(field: Boolean, flags: Int, name: Int, tpe: Int, attribs: List[Attribute])
case class Attribute(name: Int, data: Array[Byte]) {
override def toString = (pool(name): @unchecked) match {
case pool.UTF8(s) => s
}
def reader: ByteArrayReader = new ByteArrayReader(data)
}
}
|