Permalink
Browse files

Improving organization of classfile parser.

  • Loading branch information...
paulp committed Apr 26, 2012
1 parent bbdd570 commit de5aaf45603f83e3a15872df395533b6b054564b
@@ -0,0 +1,169 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal
+
+import java.io.DataInput
+import ConstantPool._
+import ClassfileConstants._
+
+trait ClassfileModel {
+ type Result
+ type Entry
+ type InterfaceInfo
+ type MemberInfo
+ type AttributeInfo
+ type InnerClassInfo
+
+ protected implicit def EntryArrayTag: ArrayTag[Entry]
+ protected implicit def InterfaceInfoArrayTag: ArrayTag[InterfaceInfo]
+ protected implicit def MemberInfoArrayTag: ArrayTag[MemberInfo]
+ protected implicit def AttributeInfoArrayTag: ArrayTag[AttributeInfo]
+ protected implicit def InnerClassInfoArrayTag: ArrayTag[InnerClassInfo]
+
+ // These could be implemented to jump forward in the stream if the
+ // result is not wanted.
+ def readConstantPoolEntry(): Entry
+ def readInterface(): InterfaceInfo
+ def readMember(): MemberInfo
+ def readAttribute(): AttributeInfo
+ def readInnerClass(): InnerClassInfo
+
+ def createInfo(
+ version: JvmVersion,
+ entries: Array[Entry],
+ flags: Int,
+ name: String,
+ superName: String,
+ interfaces: Array[InterfaceInfo],
+ fields: Array[MemberInfo],
+ methods: Array[MemberInfo],
+ attributes: Array[AttributeInfo]
+ ): Result
+}
+
+abstract class StreamingClassfileModel extends ClassfileModel {
+ protected[this] val in: DataInput
+ private[this] var name: String = _
+ private[this] var entries: Array[PoolEntry] = _
+
+ type Entry = PoolEntry
+
+ // These translate null into "", it's less troublesome.
+ protected def nameAt(idx: Int) = entries(idx) match {
+ case x: Name_Info => stringAt(x.name_index).replace('/', '.')
+ case _ => ""
+ }
+ protected def stringAt(idx: Int) = entries(idx) match {
+ case x: Utf8_info => x.stringValue
+ case _ => ""
+ }
+
+ protected def u4 = in.readInt
+ protected def u2 = in.readUnsignedShort.toChar
+ protected def u1 = in.readUnsignedByte
+
+ // The constant_pool table is indexed from 1 to constant_pool_count−1.
+ protected def readConstantPool(): Array[Entry] = {
+ val count = u2
+ val entries = new Array[Entry](count)
+ var i = 1
+ while (i < count) {
+ val entry = readConstantPoolEntry()
+ entries(i) = entry
+ i += entry.width
+ }
+ entries
+ }
+ protected def readInterfaces() = {
+ val count = u2
+ val interfaces = new Array[InterfaceInfo](count)
+ var i = 0
+ while (i < count) {
+ interfaces(i) = readInterface()
+ i += 1
+ }
+ interfaces
+ }
+ protected def readMembers() = {
+ val count = u2
+ val arr = new Array[MemberInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readMember()
+ i += 1
+ }
+ arr
+ }
+ protected def readAttributes(): Array[AttributeInfo] = {
+ val count = u2
+ val arr = new Array[AttributeInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readAttribute()
+ i += 1
+ }
+ arr
+ }
+ protected def readInnerClasses() = {
+ val count = u2
+ val arr = new Array[InnerClassInfo](count)
+ var i = 0
+ while (i < count) {
+ arr(i) = readInnerClass()
+ i += 1
+ }
+ arr
+ }
+ protected def thisClass = name
+
+ def parse() = {
+ assert(u4 == JAVA_MAGIC, "Bad magic number")
+ val version = JvmVersion(u2, u2)
+ this.entries = readConstantPool()
+ val flags = u2.toShort
+ this.name = nameAt(u2)
+ val superName = nameAt(u2)
+ val interfaces = readInterfaces()
+ val fields = readMembers()
+ val methods = readMembers()
+ val attributes = readAttributes()
+
+ try createInfo(version, entries, flags, name, superName, interfaces, fields, methods, attributes)
+ finally entries = null
+ }
+}
+
+abstract class ScalacClassfileModel extends StreamingClassfileModel {
+ type Result = JvmClassInfo
+ type InterfaceInfo = String
+ type MemberInfo = JvmMemberInfo
+ type AttributeInfo = JvmAttributeInfo
+ type InnerClassInfo = JvmInnerClassInfo
+
+ protected implicit def EntryArrayTag = arrayTag[PoolEntry]
+ protected implicit def InterfaceInfoArrayTag = arrayTag[InterfaceInfo]
+ protected implicit def MemberInfoArrayTag = arrayTag[MemberInfo]
+ protected implicit def AttributeInfoArrayTag = arrayTag[AttributeInfo]
+ protected implicit def InnerClassInfoArrayTag = arrayTag[InnerClassInfo]
+
+ def readConstantPoolEntry(): PoolEntry
+ def readInterface(): String
+ def readMember(): JvmMemberInfo
+ def readAttribute(): JvmAttributeInfo
+ def readInnerClass(): JvmInnerClassInfo
+
+ def createInfo(
+ version: JvmVersion,
+ entries: Array[PoolEntry],
+ flags: Int,
+ name: String,
+ superName: String,
+ interfaces: Array[String],
+ fields: Array[JvmMemberInfo],
+ methods: Array[JvmMemberInfo],
+ attributes: Array[JvmAttributeInfo]
+ ): JvmClassInfo = new JvmClassInfo(name, superName, interfaces, fields, methods, attributes)
+}
@@ -0,0 +1,78 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.reflect.internal
+
+import ClassfileConstants._
+
+object ConstantPool {
+ final case class JvmVersion(minorVersion: Int, majorVersion: Int)
+
+ type UShort = Char
+
+ final val CONSTANT_Utf8 = 1
+ final val CONSTANT_Integer = 3
+ final val CONSTANT_Float = 4
+ final val CONSTANT_Long = 5
+ final val CONSTANT_Double = 6
+ final val CONSTANT_Class = 7
+ final val CONSTANT_String = 8
+ final val CONSTANT_Fieldref = 9
+ final val CONSTANT_Methodref = 10
+ final val CONSTANT_InterfaceMethodref = 11
+ final val CONSTANT_NameAndType = 12
+
+ /*
+ 4.2.2 Unqualified Names
+ Names of methods, fields and local variables are stored as unqualified
+ names. Unqualified names must not contain the characters '.', ';', '['
+ or '/'. Method names are further constrained so that, with the exception
+ of the special method names <init> and <clinit> (§3.9), they must not
+ contain the characters '<' or '>'.
+
+ 4.3 Descriptors and Signatures
+ A descriptor is a string representing the type of a field or method.
+ Descriptors are represented in the class file format using modified
+ UTF-8 strings (§4.4.7) and thus may be drawn, where not further
+ constrained, from the entire Unicode character set. A signature is a
+ string representing the generic type of a field or method, or generic
+ type information for a class declaration.
+ */
+ abstract class Name_Info(tag: Byte) extends PoolEntry(tag) {
+ def name_index: UShort
+ }
+ abstract class Ref_Info(tag: Byte) extends PoolEntry(tag) {
+ def class_index: UShort
+ def name_and_type_index: UShort
+ }
+ class Class_info(val name_index: UShort) extends Name_Info(CONSTANT_Class) { }
+ class Double_info(val value: Double) extends PoolEntry(CONSTANT_Double) {
+ override def width = 2
+ }
+ class Fieldref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_Fieldref)
+ class Float_info(val value: Float) extends PoolEntry(CONSTANT_Float)
+ class Integer_info(val value: Int) extends PoolEntry(CONSTANT_Integer)
+ class InterfaceMethodref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_InterfaceMethodref)
+ class Long_info(val value: Long) extends PoolEntry(CONSTANT_Long) {
+ override def width = 2
+ }
+ class Methodref_info(val class_index: UShort, val name_and_type_index: UShort) extends Ref_Info(CONSTANT_Methodref)
+ class NameAndType_info(val name_index: UShort, val descriptor_index: UShort) extends Name_Info(CONSTANT_NameAndType) {
+ override def toString = "NameAndType #%s:#%s;".format(name_index, descriptor_index)
+ }
+ class String_info(val string_index: UShort) extends PoolEntry(CONSTANT_String) { }
+ class Utf8_info(override val stringValue: String) extends PoolEntry(CONSTANT_Utf8) {
+ override def toString = ("Asciz " + stringValue).trim
+ }
+
+ abstract class PoolEntry(tag: Byte) {
+ def width = 1
+ def stringValue: String = sys.error("Not a String-valued constant pool entry: " + this)
+ override def toString = (
+ getClass.getName.split("[.$]").last + "/" + tag
+ )
+ }
+ object NoEntry extends PoolEntry(-1) { }
+}
Oops, something went wrong.

0 comments on commit de5aaf4

Please sign in to comment.