Skip to content
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) { }
}

0 comments on commit de5aaf4

Please sign in to comment.
You can’t perform that action at this time.