icodereader.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,047 行 · 第 1/3 页

SCALA
1,047
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author Iulian Dragos */// $Id: ICodeReader.scala 14416 2008-03-19 01:17:25Z mihaylov $package scala.tools.nsc.symtab.classfileimport java.io.IOExceptionimport scala.collection.mutable._import scala.tools.nsc._import scala.tools.nsc.backend.icode._import scala.tools.nsc.io._import scala.tools.nsc.util.{Position,NoPosition}import ClassfileConstants._import Flags._/** ICode reader from Java bytecode. * *  @author Iulian Dragos *  @version 1.0 */abstract class ICodeReader extends ClassfileParser {  val global: Global  import global._  import icodes._  var instanceCode: IClass = null          // the ICode class for the current symbol  var staticCode:   IClass = null          // the ICode class static members  var method: IMethod = _                  // the current IMethod  val OBJECT: TypeKind = REFERENCE(definitions.ObjectClass)  val nothingName = newTermName("scala.runtime.Nothing$")  val nullName    = newTermName("scala.runtime.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: Symbol): (IClass, IClass) = {    var classFile: AbstractFile = null;    var sym = cls    isScalaModule = cls.isModule && !cls.hasFlag(JAVA)    log("Reading class: " + cls + " isScalaModule?: " + isScalaModule)    val name = cls.fullNameString(java.io.File.separatorChar) + (if (sym.hasFlag(MODULE)) "$" else "")    val entry = classPath.root.find(name, false)    if (entry ne null) {      classFile = entry.classFile//      if (isScalaModule)        //sym = cls.linkedClassOfModule      assert(classFile ne null, "No classfile for " + cls)//    for (s <- cls.info.members) //      Console.println("" + s + ": " + s.tpe)      this.instanceCode = new IClass(sym)      this.staticCode   = new IClass(sym.linkedClassOfClass)      parse(classFile, sym)    } else      log("Could not find: " + cls)    (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() {    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 " + c + "instead of " + clazz)    in.skip(2)               // super class    in.skip(2 * in.nextChar) // interfaces    val fieldCount = in.nextChar    for (i <- 0 until fieldCount) parseField()    val methodCount = in.nextChar    for (i <- 0 until methodCount) parseMethod();    instanceCode.methods = instanceCode.methods.reverse    staticCode.methods = staticCode.methods.reverse  }  override def parseField() {    val (jflags, sym) = parseMember(true)    getCode(jflags).addField(new IField(sym))    skipAttributes()  }  private def parseMember(field: Boolean): (Int, Symbol) = {    val jflags = in.nextChar    val name = pool.getName(in.nextChar)    var tpe  = pool.getType(in.nextChar)    if (name == nme.CONSTRUCTOR)      tpe match {        case MethodType(formals, restpe) =>          assert(restpe.typeSymbol == definitions.UnitClass)          tpe = MethodType(formals, getOwner(jflags).tpe)      }    if ("<clinit>" == name.toString)       (jflags, NoSymbol)    else {      val owner = getOwner(jflags)      var sym = owner.info.member(name).suchThat(old => sameType(old.tpe, tpe));      if (sym == NoSymbol)        sym = owner.info.member(newTermName(name.toString + nme.LOCAL_SUFFIX)).suchThat(old => old.tpe =:= tpe);      if (sym == NoSymbol) {        log("Could not find symbol for " + name + ": " + tpe/* + " in " + owner.info.decls*/)        log(owner.info.member(name).tpe + " : " + tpe)        if (field)          sym = owner.newValue(owner.pos, name).setInfo(tpe).setFlag(MUTABLE | javaToScalaFlags(jflags))        else          sym = owner.newMethod(owner.pos, name).setInfo(tpe).setFlag(javaToScalaFlags(jflags))        owner.info.decls.enter(sym)        log("added " + sym + ": " + sym.tpe)      }      (jflags, sym)    }  }  private def javaToScalaFlags(flags: Int): Long = {    import ch.epfl.lamp.fjbg.JAccessFlags._        var res = 0L    if ((flags & ACC_PRIVATE) == 1) res |= Flags.PRIVATE    if ((flags & ACC_PROTECTED) == 1) res |= Flags.PROTECTED    if ((flags & ACC_FINAL) == 1) res |= Flags.FINAL    if ((flags & ACC_ABSTRACT) == 1) res |= Flags.DEFERRED    if ((flags & ACC_SYNTHETIC) == 1) res |= Flags.SYNTHETIC    res  }    /** Checks if tp1 is the same type as tp2, modulo implict methods.   *  We don't care about the distinction between implcit and explicit   *  methods as this point, and we can't get back the information from   *  bytecode anyway.   */  private def sameType(tp1: Type, tp2: Type): Boolean = (tp1, tp2) match {    case (MethodType(args1, resTpe1), MethodType(args2, resTpe2)) =>      if (tp1.isInstanceOf[ImplicitMethodType] || tp2.isInstanceOf[ImplicitMethodType]) {        MethodType(args1, resTpe1) =:= MethodType(args2, resTpe2)      } else        tp1 =:= tp2    case _ => tp1 =:= tp2  }    override def parseMethod() {    val (jflags, sym) = parseMember(false)    if (sym != NoSymbol) {      log("Parsing method " + sym.fullNameString + ": " + sym.tpe);      this.method = new IMethod(sym);      this.method.returnType = toTypeKind(sym.tpe.resultType)      getCode(jflags).addMethod(this.method)      if ((jflags & JAVA_ACC_NATIVE) != 0)        this.method.native = true      val attributeCount = in.nextChar      for (i <- 0 until attributeCount) parseAttribute()    } else {      if (settings.debug.value) log("Skipping non-existent method.");      skipAttributes();    }  }  def parseAttribute() {    val attrName = pool.getName(in.nextChar)    val attrLen = in.nextInt    attrName match {      case nme.CodeATTR =>        parseByteCode()      case _ =>        in.skip(attrLen)    }  }  override def classNameToSymbol(name: Name) = {     val sym = if (name == nothingName)      definitions.AllClass    else if (name == nullName)      definitions.AllRefClass    else if (name.endsWith("$class")) {      val iface = definitions.getClass(name.subName(0, name.length - "$class".length))      log("forcing " + iface)      iface.info // force the mixin type-transformer      definitions.getClass(name)    } else if (name.endsWith("$"))      definitions.getModule(name.subName(0, name.length - 1))    else      definitions.getClass(name)        //super.classNameToSymbol(name)    if (sym.isModule)      sym.moduleClass    else      sym  }    var maxStack: Int = _  var maxLocals: Int = _  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() {    maxStack = in.nextChar    maxLocals = in.nextChar    val codeLength = in.nextInt    val code = new LinearCode    def parseInstruction {      import opcodes._      import code._      var size = 1 // instruction size      /** Parse 16 bit jump target. */      def parseJumpTarget = {        size = size + 2        val offset = in.nextChar.asInstanceOf[Short]        val target = pc + offset        assert(target >= 0 && target < codeLength, "Illegal jump target: " + target)        target      }      /** Parse 32 bit jump target. */      def parseJumpTargetW: Int = {        size += 4        val offset = in.nextInt        val target = pc + offset        assert(target >= 0 && target < codeLength, "Illegal jump target: " + target + "pc: " + pc + " offset: " + offset)        target      }      val instr = toUnsignedByte(in.nextByte)      instr match {        case JVM.nop => parseInstruction        case JVM.aconst_null => code.emit(CONSTANT(Constant(null)))        case JVM.iconst_m1   => code.emit(CONSTANT(Constant(-1)))        case JVM.iconst_0    => code.emit(CONSTANT(Constant(0)))        case JVM.iconst_1    => code.emit(CONSTANT(Constant(1)))        case JVM.iconst_2    => code.emit(CONSTANT(Constant(2)))        case JVM.iconst_3    => code.emit(CONSTANT(Constant(3)))        case JVM.iconst_4    => code.emit(CONSTANT(Constant(4)))        case JVM.iconst_5    => code.emit(CONSTANT(Constant(5)))        case JVM.lconst_0    => code.emit(CONSTANT(Constant(0l)))        case JVM.lconst_1    => code.emit(CONSTANT(Constant(1l)))        case JVM.fconst_0    => code.emit(CONSTANT(Constant(0.0f)))        case JVM.fconst_1    => code.emit(CONSTANT(Constant(1.0f)))        case JVM.fconst_2    => code.emit(CONSTANT(Constant(2.0f)))        case JVM.dconst_0    => code.emit(CONSTANT(Constant(0.0)))        case JVM.dconst_1    => code.emit(CONSTANT(Constant(1.0)))        case JVM.bipush      => code.emit(CONSTANT(Constant(in.nextByte))); size += 1        case JVM.sipush      => code.emit(CONSTANT(Constant(in.nextChar))); size += 2        case JVM.ldc         => code.emit(CONSTANT(pool.getConstant(toUnsignedByte(in.nextByte)))); size += 1         case JVM.ldc_w       => code.emit(CONSTANT(pool.getConstant(in.nextChar))); size += 2        case JVM.ldc2_w      => code.emit(CONSTANT(pool.getConstant(in.nextChar))); size += 2        case JVM.iload       => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, INT)));    size += 1        case JVM.lload       => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, LONG)));   size += 1        case JVM.fload       => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, FLOAT)));  size += 1        case JVM.dload       => code.emit(LOAD_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size += 1        case JVM.aload       =>           val local = in.nextByte; size += 1          if (local == 0 && !method.isStatic)            code.emit(THIS(method.symbol.owner));          else            code.emit(LOAD_LOCAL(code.getLocal(local, OBJECT)));	        case JVM.iload_0     => code.emit(LOAD_LOCAL(code.getLocal(0, INT)))        case JVM.iload_1     => code.emit(LOAD_LOCAL(code.getLocal(1, INT)))        case JVM.iload_2     => code.emit(LOAD_LOCAL(code.getLocal(2, INT)))        case JVM.iload_3     => code.emit(LOAD_LOCAL(code.getLocal(3, INT)))        case JVM.lload_0     => code.emit(LOAD_LOCAL(code.getLocal(0, LONG)))        case JVM.lload_1     => code.emit(LOAD_LOCAL(code.getLocal(1, LONG)))        case JVM.lload_2     => code.emit(LOAD_LOCAL(code.getLocal(2, LONG)))        case JVM.lload_3     => code.emit(LOAD_LOCAL(code.getLocal(3, LONG)))        case JVM.fload_0     => code.emit(LOAD_LOCAL(code.getLocal(0, FLOAT)))        case JVM.fload_1     => code.emit(LOAD_LOCAL(code.getLocal(1, FLOAT)))        case JVM.fload_2     => code.emit(LOAD_LOCAL(code.getLocal(2, FLOAT)))        case JVM.fload_3     => code.emit(LOAD_LOCAL(code.getLocal(3, FLOAT)))        case JVM.dload_0     => code.emit(LOAD_LOCAL(code.getLocal(0, DOUBLE)))        case JVM.dload_1     => code.emit(LOAD_LOCAL(code.getLocal(1, DOUBLE)))        case JVM.dload_2     => code.emit(LOAD_LOCAL(code.getLocal(2, DOUBLE)))        case JVM.dload_3     => code.emit(LOAD_LOCAL(code.getLocal(3, DOUBLE)))        case JVM.aload_0     =>          if (!method.isStatic)            code.emit(THIS(method.symbol.owner));          else            code.emit(LOAD_LOCAL(code.getLocal(0, OBJECT)));        case JVM.aload_1     => code.emit(LOAD_LOCAL(code.getLocal(1, OBJECT)))        case JVM.aload_2     => code.emit(LOAD_LOCAL(code.getLocal(2, OBJECT)))        case JVM.aload_3     => code.emit(LOAD_LOCAL(code.getLocal(3, OBJECT)))        case JVM.iaload      => code.emit(LOAD_ARRAY_ITEM(INT))        case JVM.laload      => code.emit(LOAD_ARRAY_ITEM(LONG))        case JVM.faload      => code.emit(LOAD_ARRAY_ITEM(FLOAT))        case JVM.daload      => code.emit(LOAD_ARRAY_ITEM(DOUBLE))        case JVM.aaload      => code.emit(LOAD_ARRAY_ITEM(OBJECT))        case JVM.baload      => code.emit(LOAD_ARRAY_ITEM(BYTE))        case JVM.caload      => code.emit(LOAD_ARRAY_ITEM(CHAR))        case JVM.saload      => code.emit(LOAD_ARRAY_ITEM(SHORT))        case JVM.istore      => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, INT)));    size += 1        case JVM.lstore      => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, LONG)));   size += 1        case JVM.fstore      => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, FLOAT)));  size += 1        case JVM.dstore      => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, DOUBLE))); size += 1        case JVM.astore      => code.emit(STORE_LOCAL(code.getLocal(in.nextByte, OBJECT))); size += 1        case JVM.istore_0    => code.emit(STORE_LOCAL(code.getLocal(0, INT)))        case JVM.istore_1    => code.emit(STORE_LOCAL(code.getLocal(1, INT)))        case JVM.istore_2    => code.emit(STORE_LOCAL(code.getLocal(2, INT)))        case JVM.istore_3    => code.emit(STORE_LOCAL(code.getLocal(3, INT)))        case JVM.lstore_0    => code.emit(STORE_LOCAL(code.getLocal(0, LONG)))        case JVM.lstore_1    => code.emit(STORE_LOCAL(code.getLocal(1, LONG)))        case JVM.lstore_2    => code.emit(STORE_LOCAL(code.getLocal(2, LONG)))        case JVM.lstore_3    => code.emit(STORE_LOCAL(code.getLocal(3, LONG)))        case JVM.fstore_0    => code.emit(STORE_LOCAL(code.getLocal(0, FLOAT)))        case JVM.fstore_1    => code.emit(STORE_LOCAL(code.getLocal(1, FLOAT)))        case JVM.fstore_2    => code.emit(STORE_LOCAL(code.getLocal(2, FLOAT)))        case JVM.fstore_3    => code.emit(STORE_LOCAL(code.getLocal(3, FLOAT)))        case JVM.dstore_0    => code.emit(STORE_LOCAL(code.getLocal(0, DOUBLE)))        case JVM.dstore_1    => code.emit(STORE_LOCAL(code.getLocal(1, DOUBLE)))        case JVM.dstore_2    => code.emit(STORE_LOCAL(code.getLocal(2, DOUBLE)))        case JVM.dstore_3    => code.emit(STORE_LOCAL(code.getLocal(3, DOUBLE)))        case JVM.astore_0    => code.emit(STORE_LOCAL(code.getLocal(0, OBJECT)))        case JVM.astore_1    => code.emit(STORE_LOCAL(code.getLocal(1, OBJECT)))        case JVM.astore_2    => code.emit(STORE_LOCAL(code.getLocal(2, OBJECT)))        case JVM.astore_3    => code.emit(STORE_LOCAL(code.getLocal(3, OBJECT)))        case JVM.iastore     => code.emit(STORE_ARRAY_ITEM(INT))        case JVM.lastore     => code.emit(STORE_ARRAY_ITEM(LONG))        case JVM.fastore     => code.emit(STORE_ARRAY_ITEM(FLOAT))        case JVM.dastore     => code.emit(STORE_ARRAY_ITEM(DOUBLE))        case JVM.aastore     => code.emit(STORE_ARRAY_ITEM(OBJECT))        case JVM.bastore     => code.emit(STORE_ARRAY_ITEM(BYTE))        case JVM.castore     => code.emit(STORE_ARRAY_ITEM(CHAR))        case JVM.sastore     => code.emit(STORE_ARRAY_ITEM(SHORT))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?