summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2006-10-16 15:55:49 +0000
committerIulian Dragos <jaguarul@gmail.com>2006-10-16 15:55:49 +0000
commite909afb83fe2398b5564262321272d98cd624333 (patch)
treec9a7056df093d86f97098ca5fd22941bdfb87a8c
parent0618391c55a377937f11aa765d0a8cce4404143c (diff)
downloadscala-e909afb83fe2398b5564262321272d98cd624333.tar.gz
scala-e909afb83fe2398b5564262321272d98cd624333.tar.bz2
scala-e909afb83fe2398b5564262321272d98cd624333.zip
Fixed many bugs in icodeReader and added basic ...
Fixed many bugs in icodeReader and added basic blocks.
-rw-r--r--lib/fjbg.jar.desired.sha12
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala3
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala9
-rw-r--r--src/compiler/scala/tools/nsc/symtab/StdNames.scala8
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala49
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala117
8 files changed, 162 insertions, 31 deletions
diff --git a/lib/fjbg.jar.desired.sha1 b/lib/fjbg.jar.desired.sha1
index 5b958aca43..8a6abac347 100644
--- a/lib/fjbg.jar.desired.sha1
+++ b/lib/fjbg.jar.desired.sha1
@@ -1 +1 @@
-e14fd4c3cac457637bb3d0019280f27302185d64 ?fjbg.jar
+47cc318f5e59782526656e8884b1b2bacde5c552 ?fjbg.jar
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index ad5411ddc6..1363d4fecb 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -88,7 +88,8 @@ trait BasicBlocks requires ICodes {
instructionList.length;
/** Return the index of the instruction which produced the value
- * consumed by the given instruction. */
+ * consumed by the given instruction.
+ */
def findDef(pos: Int): Option[Int] = {
assert(closed);
var i = pos;
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 6bb0a4eb9b..f78a53a623 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -58,7 +58,6 @@ abstract class GenJVM extends SubComponent {
*/
class BytecodeGenerator {
val MIN_SWITCH_DENSITY = 0.7
- val MODULE_INSTANCE_NAME = "MODULE$"
val JAVA_LANG_STRINGBUFFER = "java.lang.StringBuffer"
val stringBufferType = new JObjectType(JAVA_LANG_STRINGBUFFER)
@@ -468,7 +467,7 @@ abstract class GenJVM extends SubComponent {
def addModuleInstanceField: Unit = {
import JAccessFlags._
jclass.addNewField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC,
- MODULE_INSTANCE_NAME,
+ nme.MODULE_INSTANCE_FIELD.toString,
jclass.getType())
}
@@ -530,7 +529,7 @@ abstract class GenJVM extends SubComponent {
paramNames);
val mirrorCode = mirrorMethod.getCode().asInstanceOf[JExtendedCode];
mirrorCode.emitGETSTATIC(moduleName,
- MODULE_INSTANCE_NAME,
+ nme.MODULE_INSTANCE_FIELD.toString,
new JObjectType(moduleName));
var i = 0
var index = 0
@@ -720,7 +719,7 @@ abstract class GenJVM extends SubComponent {
log("genearting LOAD_MODULE for: " + module + " flags: " +
Flags.flagsToString(module.flags));
jcode.emitGETSTATIC(javaName(module) /* + "$" */ ,
- MODULE_INSTANCE_NAME,
+ nme.MODULE_INSTANCE_FIELD.toString,
javaType(module));
case STORE_ARRAY_ITEM(kind) =>
@@ -782,7 +781,7 @@ abstract class GenJVM extends SubComponent {
isModuleInitialized = true;
jcode.emitALOAD_0();
jcode.emitPUTSTATIC(jclass.getName(),
- MODULE_INSTANCE_NAME,
+ nme.MODULE_INSTANCE_FIELD.toString,
jclass.getType());
}
diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
index 2aafcdbd48..0e7c2a6b19 100644
--- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala
+++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala
@@ -83,6 +83,8 @@ trait StdNames requires SymbolTable {
val LOCALDUMMY_PREFIX = newTermName(LOCALDUMMY_PREFIX_STRING)
val THIS_SUFFIX = newTermName(".this")
+ val MODULE_INSTANCE_FIELD = newTermName("MODULE$")
+
def isLocalName(name: Name) = name.endsWith(LOCAL_SUFFIX)
def isSetterName(name: Name) = name.endsWith(SETTER_SUFFIX)
def isLocalDummyName(name: Name) = name.startsWith(LOCALDUMMY_PREFIX)
@@ -135,6 +137,12 @@ trait StdNames requires SymbolTable {
def superName(name: Name) = newTermName("super$" + name)
+ /** The name of an accessor for protected symbols. */
+ def protName(name: Name): Name = newTermName("protected$" + name)
+
+ /** The name of a setter for protected symbols. Used for inherited Java fields. */
+ def protSetterName(name: Name): Name = newTermName("protected$set" + name)
+
val ERROR = newTermName("<error>")
val ERRORtype = newTypeName("<error>")
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
index 049fb717ff..fd9fecad8c 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala
@@ -98,7 +98,8 @@ abstract class SymbolLoaders {
/** Is the given name a valid input file base name? */
def isValid(name: String): boolean =
- name.length() > 0 && !name.endsWith("$class") && name.indexOf("$anon") == -1;
+ name.length() > 0 && (settings.XbytecodeRead.value ||
+ (!name.endsWith("$class") && name.indexOf("$anon") == -1));
def enterPackage(str: String, completer: SymbolLoader): unit = {
val pkg = root.newPackage(NoPos, newTermName(str))
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala
index ca7cd768a5..e55564ad49 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileConstants.scala
@@ -263,7 +263,7 @@ object ClassfileConstants {
final val areturn = 0xb0
final val return_ = 0xb1
- final val gestatic = 0xb2
+ final val getstatic = 0xb2
final val putstatic = 0xb3
final val getfield = 0xb4
final val putfield = 0xb5
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 8a29f31912..c53e400b4a 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -164,7 +164,9 @@ abstract class ClassfileParser {
val start = starts(index)
if (in.buf(start) != CONSTANT_CLASS) errorBadTag(start)
val name = getExternalName(in.getChar(start + 1))
- if (name.pos('.') == name.length)
+ if (name.endsWith("$"))
+ c = definitions.getModule(name.subName(0, name.length - 1))
+ else if (name.pos('.') == name.length)
c = definitions.getMember(definitions.EmptyPackageClass, name.toTypeName)
else
c = definitions.getClass(name)
@@ -173,6 +175,10 @@ abstract class ClassfileParser {
c
}
+ /** Return the symbol of the class member at <code>index</code>.
+ * If the member refers to special MODULE$ static field, return
+ * the symbol of the corresponding module.
+ */
def getMemberSymbol(index: Int, static: Boolean): Symbol = {
if (index <= 0 || len <= index) errorBadIndex(index)
var f = values(index).asInstanceOf[Symbol]
@@ -182,9 +188,21 @@ abstract class ClassfileParser {
in.buf(start) != CONSTANT_METHODREF &&
in.buf(start) != CONSTANT_INTFMETHODREF) errorBadTag(start)
val cls = getClassSymbol(in.getChar(start + 1))
- val Pair(name, tpe) = getNameAndType(in.getChar(start + 3), cls)
- val owner = if (static) cls.linkedClassOfClass else cls
- f = owner.info.decl(name).suchThat(.tpe.=:=(tpe))
+ val Pair(name, tpe) = getNameAndType(in.getChar(start + 3), cls)
+ if (name == nme.MODULE_INSTANCE_FIELD) {
+ val index = in.getChar(start + 1)
+ val name = getExternalName(in.getChar(starts(index) + 1))
+ assert(name.endsWith("$"), "Not a module class: " + name)
+ f = definitions.getModule(name.subName(0, name.length - 1))
+ } else {
+ val owner = if (static) cls.linkedClassOfClass else cls
+ f = owner.info.decl(name).suchThat(.tpe.=:=(tpe))
+ if (f == NoSymbol) {
+ // if it's an impl class, try to find it's static member inside the class
+ assert(cls.isImplClass, "Not an implementation class: " + cls);
+ f = cls.info.decl(name).suchThat(.tpe.=:=(tpe))
+ }
+ }
assert(f != NoSymbol)
values(index) = f
}
@@ -210,6 +228,29 @@ abstract class ClassfileParser {
}
p
}
+ /** Return the type of a class constant entry. Since
+ * arrays are considered to be class types, they might
+ * appear as entries in 'newarray' or 'cast' opcodes.
+ */
+ def getClassOrArrayType(index: Int): Type = {
+ if (index <= 0 || len <= index) errorBadIndex(index)
+ val value = values(index)
+ var c: Type = null
+ if (value == null) {
+ val start = starts(index)
+ if (in.buf(start) != CONSTANT_CLASS) errorBadTag(start)
+ val name = getExternalName(in.getChar(start + 1))
+ if (name(0) == ARRAY_TAG)
+ c = sigToType(name)
+ else
+ c = definitions.getClass(name).tpe
+ values(index) = c
+ } else c = value match {
+ case _: Type => value.asInstanceOf[Type]
+ case _: Symbol => value.asInstanceOf[Symbol].tpe
+ }
+ c
+ }
def getType(index: int): Type =
sigToType(getExternalName(index))
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index 302834bc40..deff220b99 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -33,7 +33,10 @@ abstract class ICodeReader extends ClassfileParser {
val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass)
- /** Read back bytecode for the given class symbol. */
+ /** Read back bytecode for the given class symbol. It returns
+ * two IClass objects, one for static members and one
+ * for non-static members.
+ */
def readClass(cls: ClassSymbol): Pair[IClass, IClass] = {
assert(cls.classFile ne null, "No classfile for " + cls)
@@ -59,6 +62,8 @@ abstract class ICodeReader extends ClassfileParser {
for (val i <- 0 until fieldCount) parseField();
val methodCount = in.nextChar
for (val i <- 0 until methodCount) parseMethod();
+ instanceCode.methods = instanceCode.methods.reverse
+ staticCode.methods = staticCode.methods.reverse
}
override def parseField(): Unit = {
@@ -78,8 +83,9 @@ abstract class ICodeReader extends ClassfileParser {
tpe = MethodType(formals, getOwner(jflags).tpe)
}
- Console.println(getOwner(jflags).info.decls);
- val sym = getOwner(jflags).info.decl(name).suchThat(old => old.tpe =:= tpe);
+ val sym = getOwner(jflags).info.member(name).suchThat(old => old.tpe =:= tpe);
+ if (sym == NoSymbol)
+ Console.println("Could not find symbol for " + name + ": " + tpe);
// assert(sym != NoSymbol, "Could not find symbol for " + name + ": " + tpe + " in " + getOwner(jflags));
Pair(jflags, sym)
}
@@ -87,13 +93,16 @@ abstract class ICodeReader extends ClassfileParser {
override def parseMethod(): Unit = {
val Pair(jflags, sym) = parseMember();
if (sym != NoSymbol) {
+ Console.println("Parsing method " + sym.fullNameString);
this.method = new IMethod(sym);
- getCode(jflags).addMethod(method);
+ getCode(jflags).addMethod(this.method);
val attributeCount = in.nextChar;
for (val i <- 0 until attributeCount)
parseAttribute();
- } else
+ } else {
if (settings.debug.value) log("Skipping non-existent method.");
+ skipAttributes();
+ }
}
def parseAttribute(): Unit = {
@@ -112,13 +121,13 @@ abstract class ICodeReader extends ClassfileParser {
val JVM = ClassfileConstants // shorter, uppercase alias for use in case patterns
def toUnsignedByte(b: Byte): Int = b.toInt & 0xff
+ var pc = 0
/** Parse java bytecode into ICode */
def parseByteCode(): Unit = {
maxStack = in.nextChar
maxLocals = in.nextChar
val codeLength = in.nextInt
- var pc = 0
val code = new LinearCode
def parseInstruction: Unit = {
@@ -129,7 +138,7 @@ abstract class ICodeReader extends ClassfileParser {
/** Parse 16 bit jump target. */
def parseJumpTarget = {
size = size + 2
- val offset = in.nextChar
+ val offset = in.nextChar.asInstanceOf[Short]
val target = pc + offset
assert(target >= 0 && target < codeLength, "Illegal jump target: " + target)
target
@@ -382,9 +391,12 @@ abstract class ICodeReader extends ClassfileParser {
case JVM.areturn => code.emit(RETURN(OBJECT))
case JVM.return_ => code.emit(RETURN(UNIT))
- case JVM.gestatic =>
+ case JVM.getstatic =>
val field = pool.getMemberSymbol(in.nextChar, true); size = size + 2;
- code.emit(LOAD_FIELD(field, true))
+ if (field.hasFlag(Flags.MODULE))
+ code.emit(LOAD_MODULE(field))
+ else
+ code.emit(LOAD_FIELD(field, true))
case JVM.putstatic =>
val field = pool.getMemberSymbol(in.nextChar, true); size = size + 2;
code.emit(STORE_FIELD(field, true))
@@ -407,7 +419,7 @@ abstract class ICodeReader extends ClassfileParser {
else SuperCall(m.owner.name);
code.emit(CALL_METHOD(m, style))
case JVM.invokestatic =>
- val m = pool.getMemberSymbol(in.nextChar, false); size = size + 2;
+ val m = pool.getMemberSymbol(in.nextChar, true); size = size + 2;
code.emit(CALL_METHOD(m, Static(false)))
case JVM.new_ =>
@@ -428,13 +440,13 @@ abstract class ICodeReader extends ClassfileParser {
code.emit(CREATE_ARRAY(kind))
case JVM.anewarray =>
- val tpe = toTypeKind(pool.getType(in.nextChar)); size = size + 2;
+ val tpe = REFERENCE(pool.getClassSymbol(in.nextChar)); size = size + 2;
code.emit(CREATE_ARRAY(tpe))
case JVM.arraylength => code.emit(CALL_PRIMITIVE(ArrayLength(OBJECT))); // the kind does not matter
case JVM.athrow => code.emit(THROW());
- case JVM.checkcast => code.emit(CHECK_CAST(toTypeKind(pool.getType(in.nextChar)))); size = size + 2;
- case JVM.instanceof => code.emit(IS_INSTANCE(toTypeKind(pool.getType(in.nextChar)))); size = size + 2;
+ case JVM.checkcast => code.emit(CHECK_CAST(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size = size + 2;
+ case JVM.instanceof => code.emit(IS_INSTANCE(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size = size + 2;
case JVM.monitorenter => code.emit(MONITOR_ENTER());
case JVM.monitorexit => code.emit(MONITOR_EXIT());
case JVM.wide =>
@@ -462,7 +474,7 @@ abstract class ICodeReader extends ClassfileParser {
case JVM.multianewarray =>
size = size + 3
- val tpe = toTypeKind(pool.getType(in.nextChar))
+ val tpe = toTypeKind(pool.getClassOrArrayType(in.nextChar))
val dim = in.nextByte
assert(dim == 1, "Cannot handle multidimensional arrays yet.")
code.emit(CREATE_ARRAY(tpe))
@@ -477,15 +489,17 @@ abstract class ICodeReader extends ClassfileParser {
pc = pc + size
}
+ pc = 0
while (pc < codeLength) {
parseInstruction
}
- val exceptionEntries = in.nextChar
+ code.toBasicBlock
+ val exceptionEntries = in.nextChar.toInt
in.skip(8 * exceptionEntries)
skipAttributes()
- Console.println(code.toString())
+ //Console.println(code.toString())
}
/** Return the icode class that should include members with the given flags.
@@ -495,11 +509,78 @@ abstract class ICodeReader extends ClassfileParser {
if ((flags & JAVA_ACC_STATIC) != 0) staticCode else instanceCode
class LinearCode {
- var instrs: ListBuffer[Instruction] = new ListBuffer
+ var instrs: ListBuffer[Pair[Int, Instruction]] = new ListBuffer
var jmpTargets: Set[Int] = new HashSet[Int]
var locals: Map[Int, Local] = new HashMap()
- def emit(i: Instruction) = instrs += i
+ def emit(i: Instruction) = {
+// Console.println(i);
+ instrs += Pair(pc, i)
+ }
+
+ /** Break this linear code in basic block representation
+ * As a side effect, it sets the 'code' field of the current
+ */
+ def toBasicBlock: Code = {
+ import opcodes._
+
+ val code = new Code(method.symbol.name.toString);
+ method.setCode(code)
+ var bb = code.startBlock
+
+ def makeBasicBlocks: Map[Int, BasicBlock] = {
+ val block: Map[Int, BasicBlock] = new HashMap;
+ for (val pc <- jmpTargets) block += pc -> code.newBlock
+ block
+ }
+
+ val blocks = makeBasicBlocks
+ var otherBlock: BasicBlock = null
+ var disableJmpTarget = false
+
+ for (val Pair(pc, instr) <- instrs.elements) {
+// Console.println("> " + pc + ": " + instr);
+ if (jmpTargets contains pc) {
+ otherBlock = blocks(pc)
+ if (!bb.isClosed) {
+ bb.emit(JUMP(otherBlock))
+ bb.close
+ }
+ bb = otherBlock
+ }
+ instr match {
+ case LJUMP(target) =>
+ otherBlock = blocks(target)
+ bb.emit(JUMP(otherBlock))
+ bb.close
+
+ case LCJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emit(CJUMP(otherBlock, failBlock, cond, kind))
+ bb.close
+
+ case LCZJUMP(success, failure, cond, kind) =>
+ otherBlock = blocks(success)
+ val failBlock = blocks(failure)
+ bb.emit(CZJUMP(otherBlock, failBlock, cond, kind))
+ bb.close
+
+ case LSWITCH(tags, targets) =>
+ bb.emit(SWITCH(tags, targets map blocks))
+ bb.close
+
+ case RETURN(_) =>
+ bb.emit(instr)
+ bb.close
+
+ case _ =>
+ bb.emit(instr)
+ }
+ }
+
+ code
+ }
/** Return the local at given index, with the given type. */
def getLocal(idx: Int, kind: TypeKind): Local = {