diff options
5 files changed, 92 insertions, 137 deletions
diff --git a/src/scalap/scala/tools/scalap/ByteArrayReader.scala b/src/scalap/scala/tools/scalap/ByteArrayReader.scala index 2fde050782..47df499dee 100644 --- a/src/scalap/scala/tools/scalap/ByteArrayReader.scala +++ b/src/scalap/scala/tools/scalap/ByteArrayReader.scala @@ -45,23 +45,22 @@ class ByteArrayReader(content: Array[Byte]) { */ def nextChar: Char = { bp += 2 - (((buf(bp - 2) & 0xff) << 8) + (buf(bp - 1) & 0xff)).asInstanceOf[Char] + getChar(bp - 2) } /** read an integer */ def nextInt: Int = { bp += 4 - ((buf(bp - 4) & 0xff) << 24) + - ((buf(bp - 3) & 0xff) << 16) + - ((buf(bp - 2) & 0xff) << 8) + - (buf(bp - 1) & 0xff) + getInt(bp - 4) } /** read a long */ - def nextLong: Long = - (nextInt.toLong << 32) + (nextInt.toLong & 0xffffffffL) + def nextLong: Long = { + bp += 8 + getLong(bp - 8) + } /** read a float */ @@ -71,55 +70,12 @@ class ByteArrayReader(content: Array[Byte]) { */ def nextDouble: Double = java.lang.Double.longBitsToDouble(nextLong) - /** read the next integer number - */ - def nextNat: Int = { - var x = 0 - var b: Byte = 0 - do { - b = buf(bp) - bp += 1 - x = (x << 7) + (b & 0x7f) - } while ((b & 0x80) != 0) - x - } - - /** read the next signed number in big endian format - */ - def nextNum(n: Int): Long = { - var x: Long = 0 - var i: Int = 0 - while (i < n) { - x = (x << 8) + (nextByte & 0xff) - i += 1 - } - val leading: Int = 64 - (n * 8) - x << leading >> leading - } - /** read an UTF8 encoded string */ def nextUTF8(len: Int): String = { - val cs: Array[Char] = new Array(len) - var i = bp - var j = 0 + val cs = scala.io.Codec.toUTF8(buf.slice(bp, bp + len)) bp += len - while (i < bp) { - var b: Int = buf(i) & 0xFF - i += 1 - if (b >= 0xE0) { - b = ((b & 0x0F) << 12) | (buf(i) & 0x3F) << 6 - i += 1 - b = b | (buf(i) & 0x3F) - i += 1 - } else if (b >= 0xC0) { - b = ((b & 0x1F) << 6) | (buf(i) & 0x3F) - i += 1 - } - cs(j) = b.asInstanceOf[Char] - j += 1 - } - new String(cs, 0, j) + new String(cs) } /** extract a character at position bp from buf diff --git a/src/scalap/scala/tools/scalap/Classfile.scala b/src/scalap/scala/tools/scalap/Classfile.scala index dd7873f6b0..d8e43f4373 100644 --- a/src/scalap/scala/tools/scalap/Classfile.scala +++ b/src/scalap/scala/tools/scalap/Classfile.scala @@ -13,10 +13,12 @@ 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 = readPool + val pool = new Pool() val flags = in.nextChar val classname = in.nextChar val superclass = in.nextChar @@ -58,69 +60,70 @@ class Classfile(in: ByteArrayReader) { intfs } - def readPool = { - val pool = new Array[PoolEntry](in.nextChar) - var i = 1 - while (i < pool.length) { - val tag: Int = in.nextByte - tag match { - case CONSTANT_UTF8 => - pool(i) = UTF8(in.nextUTF8(in.nextChar)) - case CONSTANT_UNICODE => - in.skip(in.nextChar) - pool(i) = Empty() - case CONSTANT_CLASS => - pool(i) = ClassRef(in.nextChar) - case CONSTANT_STRING => - pool(i) = StringConst(in.nextChar) - case CONSTANT_FIELDREF => - pool(i) = FieldRef(in.nextChar, in.nextChar) - case CONSTANT_METHODREF => - pool(i) = MethodRef(in.nextChar, in.nextChar) - case CONSTANT_INTFMETHODREF => - pool(i) = IntfMethodRef(in.nextChar, in.nextChar) - case CONSTANT_NAMEANDTYPE => - pool(i) = NameAndType(in.nextChar, in.nextChar) - case CONSTANT_INTEGER => - pool(i) = IntegerConst(in.nextInt) - case CONSTANT_FLOAT => - pool(i) = FloatConst(in.nextFloat) - case CONSTANT_LONG => - pool(i) = LongConst(in.nextLong) - i = i + 1 - pool(i) = Empty() - case CONSTANT_DOUBLE => - pool(i) = DoubleConst(in.nextDouble) + 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) + 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() + pool(i) = Empty + } + else pool(i) = tag match { + case CONSTANT_UTF8 => UTF8(in.nextUTF8(in.nextChar)) + 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 } - i = i + 1 + pool } - pool - } - class PoolEntry - case class UTF8(str: String) extends PoolEntry - case class ClassRef(classId: Int) extends PoolEntry - case class FieldRef(classId: Int, memberId: Int) extends PoolEntry - case class MethodRef(classId: Int, memberId: Int) extends PoolEntry - case class IntfMethodRef(classId: Int, memberId: Int) extends PoolEntry - case class StringConst(strId: Int) extends PoolEntry - case class IntegerConst(x: Int) extends PoolEntry - case class FloatConst(x: Float) extends PoolEntry - case class LongConst(x: Long) extends PoolEntry - case class DoubleConst(x: Double) extends PoolEntry - case class NameAndType(nameId: Int, typeId: Int) extends PoolEntry - case class Empty() extends PoolEntry + 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(): String = pool(name) match { - case UTF8(str: String) => str + override def toString = pool(name) match { + case pool.UTF8(s) => s } - def reader: ByteArrayReader = new ByteArrayReader(data) } - } diff --git a/src/scalap/scala/tools/scalap/Classfiles.scala b/src/scalap/scala/tools/scalap/Classfiles.scala index e21ae76fb0..f5351f0ca5 100644 --- a/src/scalap/scala/tools/scalap/Classfiles.scala +++ b/src/scalap/scala/tools/scalap/Classfiles.scala @@ -28,6 +28,21 @@ object Classfiles { final val CONSTANT_INTFMETHODREF = 11 final val CONSTANT_NAMEANDTYPE = 12 + final val constantTagToString = Map( + CONSTANT_UTF8 -> "UTF8", + CONSTANT_UNICODE -> "Unicode", + CONSTANT_INTEGER -> "Int", + CONSTANT_FLOAT -> "Float", + CONSTANT_LONG -> "Long", + CONSTANT_DOUBLE -> "Double", + CONSTANT_CLASS -> "class", + CONSTANT_STRING -> "Asciz", + CONSTANT_FIELDREF -> "Field", + CONSTANT_METHODREF -> "Method", + CONSTANT_INTFMETHODREF -> "InterfaceMethod", + CONSTANT_NAMEANDTYPE -> "NameAndType" + ) + final val BAD_ATTR = 0x00000 final val SOURCEFILE_ATTR = 0x00001 final val SYNTHETIC_ATTR = 0x00002 diff --git a/src/scalap/scala/tools/scalap/JavaWriter.scala b/src/scalap/scala/tools/scalap/JavaWriter.scala index 06fec1a8fb..ac56975fd7 100644 --- a/src/scalap/scala/tools/scalap/JavaWriter.scala +++ b/src/scalap/scala/tools/scalap/JavaWriter.scala @@ -92,11 +92,15 @@ class JavaWriter(classfile: Classfile, writer: Writer) extends CodeWriter(writer } } - def getName(n: Int): String = cf.pool(n) match { - case cf.UTF8(str) => str - case cf.StringConst(m) => getName(m) - case cf.ClassRef(m) => getName(m) - case x => "<error>" + def getName(n: Int): String = { + import cf.pool._ + + cf.pool(n) match { + case UTF8(str) => str + case StringConst(m) => getName(m) + case ClassRef(m) => getName(m) + case _ => "<error>" + } } def getClassName(n: Int): String = nameToClass(getName(n)) diff --git a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala index bc47092f71..37bfa9cfea 100644 --- a/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala +++ b/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ClassFileParser.scala @@ -62,27 +62,7 @@ class ByteCode(val bytes : Array[Byte], val pos : Int, val length : Int) { def toInt = fold(0) { (x, b) => (x << 8) + (b & 0xFF)} def toLong = fold(0L) { (x, b) => (x << 8) + (b & 0xFF)} - // NOTE the UTF8 decoder in the Scala compiler is broken for pos > 0 - // TODO figure out patch and submit - def toUTF8String = { - val sb = new StringBuilder(length) - var i = pos - val end = pos + length - while (i < end) { - var b = bytes(i) & 0xFF - i += 1 - if (b >= 0xE0) { - b = ((b & 0x0F) << 12) | (bytes(i) & 0x3F) << 6 - b = b | (bytes(i+1) & 0x3F) - i += 2 - } else if (b >= 0xC0) { - b = ((b & 0x1F) << 6) | (bytes(i) & 0x3F) - i += 1 - } - sb += b.toChar - } - sb.toString - } + def toUTF8String = io.Codec toUTF8 (bytes drop pos take length) mkString def byte(i : Int) = bytes(pos) & 0xFF } @@ -100,9 +80,6 @@ trait ByteCodeReader extends RulesWithState { val u4 = bytes(4) ^^ (_ toInt) // should map to Long?? def bytes(n : Int) = apply(_ next n) - - - } object ClassFileParser extends ByteCodeReader { |