summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIulian Dragos <jaguarul@gmail.com>2006-11-21 10:58:17 +0000
committerIulian Dragos <jaguarul@gmail.com>2006-11-21 10:58:17 +0000
commit54ad97b77d34a977c4cf2fc10c38593a7aa4106e (patch)
treec36ed4fe7620b8c459682a32052990a61e6b35c6
parent63ceabef32e3b26d188dc6eda39eb9bf6d549bd8 (diff)
downloadscala-54ad97b77d34a977c4cf2fc10c38593a7aa4106e.tar.gz
scala-54ad97b77d34a977c4cf2fc10c38593a7aa4106e.tar.bz2
scala-54ad97b77d34a977c4cf2fc10c38593a7aa4106e.zip
Added support for modules in icode reader.
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala33
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala73
2 files changed, 78 insertions, 28 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 3640cbbb5e..0cf3714328 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -169,18 +169,21 @@ abstract class ClassfileParser {
val name = getExternalName(in.getChar(start + 1))
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)
+ c = classNameToSymbol(name)
values(index) = c
}
c
}
/** Return the symbol of the class member at <code>index</code>.
- * If the member refers to special MODULE$ static field, return
+ * The following special cases exist:
+ * - If the member refers to special MODULE$ static field, return
* the symbol of the corresponding module.
+ * - If the member is a field, and is not found with the given name,
+ * another try is made by appending nme.LOCAL_SUFFIX
+ * - If no symbol is found in the right tpe, a new try is made in the
+ * companion class, in case the owner is an implementation class.
*/
def getMemberSymbol(index: Int, static: Boolean): Symbol = {
if (index <= 0 || len <= index) errorBadIndex(index)
@@ -200,6 +203,8 @@ abstract class ClassfileParser {
} else {
val owner = if (static) cls.linkedClassOfClass else cls
f = owner.info.decl(name).suchThat(.tpe.=:=(tpe))
+ if (f == NoSymbol)
+ f = owner.info.decl(newTermName(name.toString + nme.LOCAL_SUFFIX)).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: " + owner + " couldn't find " + name + ": " + tpe);
@@ -320,11 +325,7 @@ abstract class ClassfileParser {
while (name(index) != ';') { index = index + 1 }
val end = index
index = index + 1
- val clsName = name.subName(start, end)
- if (clsName.pos('.') == clsName.length)
- definitions.getMember(definitions.EmptyPackageClass, clsName.toTypeName).tpe
- else
- definitions.getClass(clsName).tpe
+ classNameToSymbol(name.subName(start, end)).tpe
case ARRAY_TAG =>
while ('0' <= name(index) && name(index) <= '9') index = index + 1
appliedType(definitions.ArrayClass.tpe, List(sig2type))
@@ -335,6 +336,14 @@ abstract class ClassfileParser {
sig2type
}
+ /** Return the class symbol of the given name. */
+ def classNameToSymbol(name: Name) =
+ if (name.pos('.') == name.length)
+ definitions.getMember(definitions.EmptyPackageClass, name.toTypeName)
+ else
+ definitions.getClass(name)
+
+
var sawPrivateConstructor = false
def parseClass(): unit = {
@@ -405,7 +414,7 @@ abstract class ClassfileParser {
val jflags = in.nextChar
var sflags = transFlags(jflags)
if ((sflags & FINAL) == 0) sflags = sflags | MUTABLE
- if ((sflags & PRIVATE) != 0) {
+ if ((sflags & PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
@@ -422,14 +431,14 @@ abstract class ClassfileParser {
def parseMethod(): unit = {
val jflags = in.nextChar
var sflags = transFlags(jflags)
- if ((jflags & JAVA_ACC_PRIVATE) != 0) {
+ if ((jflags & JAVA_ACC_PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
val name = pool.getName(in.nextChar)
if (name == nme.CONSTRUCTOR)
sawPrivateConstructor = true
in.skip(2); skipAttributes()
} else {
if ((jflags & JAVA_ACC_BRIDGE) != 0) sflags = sflags | PRIVATE
- if ((sflags & PRIVATE) != 0) {
+ if ((sflags & PRIVATE) != 0 && !global.settings.XbytecodeRead.value) {
in.skip(4); skipAttributes()
} else {
val name = pool.getName(in.nextChar)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
index deff220b99..0c8508b0b2 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala
@@ -32,29 +32,48 @@ abstract class ICodeReader extends ClassfileParser {
var method: IMethod = _ // the current IMethod
val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass)
+ val nothingName = newTermName("scala.Nothing$")
+ val nullName = newTermName("scala.Null$")
+ var isScalaModule = false
/** 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)
-
+ def readClass(cls: Symbol): Pair[IClass, IClass] = {
+ var classFile: AbstractFile = null;
+ isScalaModule = cls.isModule && !cls.hasFlag(JAVA)
+ if (isScalaModule) {
+ Console.println("Loading module: " + cls);
+ classFile = classPath.root.find(cls.fullNameString(java.io.File.separatorChar) + "$", false).classFile
+ } else
+ classFile = cls.asInstanceOf[ClassSymbol].classFile
+ assert(classFile ne null, "No classfile for " + cls)
+
+ for (val s <- cls.info.members)
+ Console.println("" + s + ": " + s.tpe)
this.instanceCode = new IClass(cls)
this.staticCode = new IClass(cls.linkedClassOfModule)
- parse(cls.classFile, cls)
+ parse(classFile, cls)
Pair(staticCode, instanceCode)
}
+ /** If we're parsing a scala module, the owner of members is always
+ * the module symbol.
+ */
+ override def getOwner(jflags: Int): Symbol = {
+ if (isScalaModule) this.staticModule else super.getOwner(jflags)
+ }
+
override def parseClass(): Unit = {
val jflags = in.nextChar
val isAttribute = (jflags & JAVA_ACC_ANNOTATION) != 0
var sflags = transFlags(jflags)
if ((sflags & DEFERRED) != 0) sflags = sflags & ~DEFERRED | ABSTRACT
val c = pool.getClassSymbol(in.nextChar)
- if (c != clazz)
- throw new IOException("class file '" + in.file + "' contains wrong " + clazz)
+// if (c != clazz)
+// throw new IOException("class file '" + in.file + "' contains " + c + "instead of " + clazz)
in.skip(2) // super class
in.skip(2 * in.nextChar) // interfaces
@@ -83,11 +102,16 @@ abstract class ICodeReader extends ClassfileParser {
tpe = MethodType(formals, getOwner(jflags).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)
+ if ("<clinit>" == name.toString)
+ Pair(jflags, NoSymbol)
+ else {
+ var sym = getOwner(jflags).info.member(name).suchThat(old => old.tpe =:= tpe);
+ if (sym == NoSymbol)
+ sym = getOwner(jflags).info.member(newTermName(name.toString + nme.LOCAL_SUFFIX)).suchThat(old => old.tpe =:= tpe);
+ if (sym == NoSymbol)
+ Console.println("Could not find symbol for " + name + ": " + tpe);
+ Pair(jflags, sym)
+ }
}
override def parseMethod(): Unit = {
@@ -116,6 +140,17 @@ abstract class ICodeReader extends ClassfileParser {
}
}
+ override def classNameToSymbol(name: Name) =
+ if (name == nothingName)
+ definitions.AllClass
+ else if (name == nullName)
+ definitions.AllRefClass
+ else if (name.endsWith("$"))
+ definitions.getModule(name.subName(0, name.length - 1))
+ else
+ definitions.getClass(name)
+
+
var maxStack: Int = _
var maxLocals: Int = _
val JVM = ClassfileConstants // shorter, uppercase alias for use in case patterns
@@ -489,6 +524,13 @@ abstract class ICodeReader extends ClassfileParser {
pc = pc + size
}
+ // add parameters
+ var idx = if (method.isStatic) 0 else 1
+ for (val t <- method.symbol.tpe.paramTypes) {
+ this.method.addParam(code.freshLocal(idx, toTypeKind(t), true))
+ idx = idx + 1
+ }
+
pc = 0
while (pc < codeLength) {
parseInstruction
@@ -539,7 +581,7 @@ abstract class ICodeReader extends ClassfileParser {
var disableJmpTarget = false
for (val Pair(pc, instr) <- instrs.elements) {
-// Console.println("> " + pc + ": " + instr);
+ Console.println("> " + pc + ": " + instr);
if (jmpTargets contains pc) {
otherBlock = blocks(pc)
if (!bb.isClosed) {
@@ -606,7 +648,7 @@ abstract class ICodeReader extends ClassfileParser {
l
case None =>
checkValidIndex
- val l = freshLocal(idx, kind)
+ val l = freshLocal(idx, kind, false)
locals += idx -> l
l
}
@@ -615,11 +657,10 @@ abstract class ICodeReader extends ClassfileParser {
override def toString(): String = instrs.toList.mkString("", "\n", "")
/** Return a fresh Local variable.
- * TODO: 'isArgument' is always false, should be modified accordingly.
*/
- def freshLocal(idx: Int, kind: TypeKind) = {
+ def freshLocal(idx: Int, kind: TypeKind, isArg: Boolean) = {
val sym = method.symbol.newVariable(NoPos, "loc" + idx).setInfo(kind.toType);
- new Local(sym, kind, false)
+ new Local(sym, kind, isArg)
}
/** Base class for branch instructions that take addresses. */