classfileparser.scala

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

SCALA
821
字号
/* NSC -- new Scala compiler * Copyright 2005-2008 LAMP/EPFL * @author  Martin Odersky */// $Id: ClassfileParser.scala 14134 2008-02-26 09:50:05Z odersky $package scala.tools.nsc.symtab.classfileimport java.io.IOExceptionimport java.lang.Integer.toHexStringimport scala.collection.immutable.{Map, ListMap}import scala.collection.mutable.{ListBuffer, ArrayBuffer}import scala.tools.nsc.io.AbstractFileimport scala.tools.nsc.util.{Position, NoPosition}/** This abstract class implements a class file parser. * *  @author Martin Odersky *  @version 1.0 */abstract class ClassfileParser {  def sourcePath : AbstractFile = null  val global: Global  import global._  import ClassfileConstants._  import Flags._  protected var in: AbstractFileReader = _  // the class file reader  protected var clazz: Symbol = _           // the class symbol containing dynamic members  protected var staticModule: Symbol = _    // the module symbol containing static members  protected var instanceDefs: Scope = _     // the scope of all instance definitions  protected var staticDefs: Scope = _       // the scope of all static definitions  protected var pool: ConstantPool = _      // the classfile's constant pool  protected var isScala: Boolean = _        // does class file describe a scala class?  protected var hasMeta: Boolean = _        // does class file contain jaco meta attribute?s  protected var busy: Boolean = false       // lock to detect recursive reads  protected var classTParams = Map[Name,Symbol]()  private object metaParser extends MetaParser {    val global: ClassfileParser.this.global.type = ClassfileParser.this.global  }  private object unpickler extends UnPickler {    val global: ClassfileParser.this.global.type = ClassfileParser.this.global  }  def parse(file: AbstractFile, root: Symbol) = try {    def handleError(e: Exception) = {      if (settings.debug.value) e.printStackTrace() //debug      throw new IOException("class file '" + in.file + "' is broken\n(" + {        if (e.getMessage() != null) e.getMessage()        else e.getClass.toString      } + ")")    }    assert(!busy)    busy = true    /*root match {      case cs: ClassSymbol =>        cs.classFile = file      case ms: ModuleSymbol =>        ms.moduleClass.asInstanceOf[ClassSymbol].classFile = file      case _ =>        println("Skipping class: " + root + ": " + root.getClass)    }*/    this.in = new AbstractFileReader(file)    if (root.isModule) {      this.clazz = root.linkedClassOfModule      this.staticModule = root    } else {      this.clazz = root      this.staticModule = root.linkedModuleOfClass    }    this.isScala = false    this.hasMeta = false    try {      parseHeader      this.pool = new ConstantPool      parseClass()    } catch {      case e: FatalError => handleError(e)      case e: RuntimeException => handleError(e)    }  } finally {    busy = false  }  protected def statics: Symbol = staticModule.moduleClass  private def parseHeader {    val magic = in.nextInt    if (magic != JAVA_MAGIC)      throw new IOException("class file '" + in.file + "' "                            + "has wrong magic number 0x" + toHexString(magic)                            + ", should be 0x" + toHexString(JAVA_MAGIC))    val minorVersion = in.nextChar    val majorVersion = in.nextChar    if ((majorVersion < JAVA_MAJOR_VERSION) ||        ((majorVersion == JAVA_MAJOR_VERSION) &&         (minorVersion < JAVA_MINOR_VERSION)))      throw new IOException("class file '" + in.file + "' "                            + "has unknown version "                            + majorVersion + "." + minorVersion                            + ", should be at least "                            + JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION)  }  class ConstantPool {    private val len = in.nextChar    private val starts = new Array[Int](len)    private val values = new Array[AnyRef](len)    private val internalized = new Array[Name](len)    { var i = 1      while (i < starts.length) {        starts(i) = in.bp        i += 1        in.nextByte match {          case CONSTANT_UTF8 | CONSTANT_UNICODE =>            in.skip(in.nextChar)          case CONSTANT_CLASS | CONSTANT_STRING =>            in.skip(2)          case CONSTANT_FIELDREF | CONSTANT_METHODREF | CONSTANT_INTFMETHODREF             | CONSTANT_NAMEANDTYPE | CONSTANT_INTEGER | CONSTANT_FLOAT =>            in.skip(4)          case CONSTANT_LONG | CONSTANT_DOUBLE =>            in.skip(8)            i += 1          case _ =>            errorBadTag(in.bp - 1)        }      }    }    def getName(index: Int): Name = {      if (index <= 0 || len <= index) errorBadIndex(index)      var name = values(index).asInstanceOf[Name]      if (name eq null) {        val start = starts(index)        if (in.buf(start) != CONSTANT_UTF8) errorBadTag(start)        name = newTermName(in.buf, start + 3, in.getChar(start + 1))        values(index) = name      }      name    }    def getExternalName(index: Int): Name = {      if (index <= 0 || len <= index) errorBadIndex(index)      if (internalized(index) eq null) {        internalized(index) = getName(index).replace('/', '.')      }      internalized(index)    }    def getClassSymbol(index: Int): Symbol = {      if (index <= 0 || len <= index) errorBadIndex(index)      var c = values(index).asInstanceOf[Symbol]      if (c eq null) {        val start = starts(index)        if (in.buf(start) != CONSTANT_CLASS) errorBadTag(start)        val name = getExternalName(in.getChar(start + 1))        if (name.endsWith("$"))          c = definitions.getModule(name.subName(0, name.length - 1))        else          c = classNameToSymbol(name)        values(index) = c      }      c    }        /** Return the symbol of the class member at <code>index</code>.     *  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)      var f = values(index).asInstanceOf[Symbol]      if (f eq null) {        val start = starts(index)        if (in.buf(start) != CONSTANT_FIELDREF &&            in.buf(start) != CONSTANT_METHODREF &&            in.buf(start) != CONSTANT_INTFMETHODREF) errorBadTag(start)        val ownerTpe = getClassOrArrayType(in.getChar(start + 1))        val (name, tpe) = getNameAndType(in.getChar(start + 3), ownerTpe)        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) ownerTpe.typeSymbol.linkedClassOfClass else ownerTpe.typeSymbol//          println("\t" + owner.info.member(name).tpe.widen + " =:= " + tpe)          f = owner.info.member(name).suchThat(_.tpe.widen =:= tpe)          if (f == NoSymbol)            f = owner.info.member(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(ownerTpe.typeSymbol.isImplClass, "Not an implementation class: " + owner + " couldn't find " + name + ": " + tpe + " inside: \n" + ownerTpe.members);            f = ownerTpe.member(name).suchThat(_.tpe =:= tpe)//            println("\townerTpe.decls: " + ownerTpe.decls)//            println("Looking for: " + name + ": " + tpe + " inside: " + ownerTpe.typeSymbol + "\n\tand found: " + ownerTpe.members)          }        }        assert(f != NoSymbol, "could not find " + name + ": " + tpe + "inside: \n" + ownerTpe.members)        values(index) = f      }      f     }        def getNameAndType(index: Int, ownerTpe: Type): (Name, Type) = {      if (index <= 0 || len <= index) errorBadIndex(index)      var p = values(index).asInstanceOf[(Name, Type)]      if (p eq null) {        val start = starts(index)        if (in.buf(start) != CONSTANT_NAMEANDTYPE) errorBadTag(start)        val name = getName(in.getChar(start + 1))        var tpe  = getType(in.getChar(start + 3))        if (name == nme.CONSTRUCTOR)          tpe match {            case MethodType(formals, restpe) =>              assert(restpe.typeSymbol == definitions.UnitClass)              tpe = MethodType(formals, ownerTpe)          }        p = (name, tpe)      }      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 eq 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(null, name)          values(index) = c        } else {          val sym = classNameToSymbol(name)                  /*if (name.endsWith("$")) definitions.getModule(name.subName(0, name.length - 1))                    else if (name.endsWith("$class")) definitions.getModule(name)                    else definitions.getClass(name)*/          values(index) = sym          c = sym.tpe        }      } else c = value match {          case tp: Type => tp          case cls: Symbol => cls.tpe      }      c    }    def getType(index: Int): Type =      sigToType(null, getExternalName(index))    def getSuperClass(index: Int): Symbol =      if (index == 0) definitions.AnyClass else getClassSymbol(index)    def getConstant(index: Int): Constant = {      if (index <= 0 || len <= index) errorBadIndex(index)      var value = values(index)      if (value eq null) {        val start = starts(index)        value = in.buf(start) match {          case CONSTANT_STRING =>            Constant(getName(in.getChar(start + 1)).toString())          case CONSTANT_INTEGER =>            Constant(in.getInt(start + 1))          case CONSTANT_FLOAT =>            Constant(in.getFloat(start + 1))          case CONSTANT_LONG =>            Constant(in.getLong(start + 1))          case CONSTANT_DOUBLE =>            Constant(in.getDouble(start + 1))          case CONSTANT_CLASS =>            getClassSymbol(index)          case _ =>            errorBadTag(start)        }        values(index) = value      }      value match {        case  ct: Constant => ct        case cls: Symbol   => Constant(cls.tpe)        case arr: Type     => Constant(arr)      }    }    /** Throws an exception signaling a bad constant index. */    private def errorBadIndex(index: Int) =      throw new RuntimeException("bad constant pool index: " + index + " at pos: " + in.bp)    /** Throws an exception signaling a bad tag at given address. */    private def errorBadTag(start: Int) =      throw new RuntimeException("bad constant pool tag " + in.buf(start) + " at byte " + start)  }  /** Return the class symbol of the given name. */  def classNameToSymbol(name: Name): Symbol =    if (name.pos('.') == name.length)      definitions.getMember(definitions.EmptyPackageClass, name.toTypeName)    else      definitions.getClass(name)    var sawPrivateConstructor = false    def parseClass() {    val jflags = in.nextChar    val isAnnotation = (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) {      assert(true)      if ((clazz eq NoSymbol) && (c ne NoSymbol)) { // XXX: needed for build compiler, so can't protect with inIDE        assert(true)        clazz = c      } else if (inIDE) {        assert(true)        Console.println("WRONG CLASS: expected: " + clazz + " found " + c)      } else throw new IOException("class file '" + in.file + "' contains wrong " + c)    }    val superType = if (isAnnotation) { in.nextChar; definitions.AnnotationClass.tpe }                    else pool.getSuperClass(in.nextChar).tpe    val ifaceCount = in.nextChar    var ifaces = for (i <- List.range(0, ifaceCount)) yield pool.getSuperClass(in.nextChar).tpe    if (isAnnotation) ifaces = definitions.ClassfileAnnotationClass.tpe :: ifaces    val parents = superType :: ifaces    // get the class file parser to reuse scopes.     instanceDefs = newClassScope(clazz)    staticDefs = newClassScope(statics)    val classInfo = ClassInfoType(parents, instanceDefs, clazz)    val staticInfo = ClassInfoType(List(), staticDefs, statics)    val curbp = in.bp    skipMembers() // fields    skipMembers() // methods    parseAttributes(clazz, classInfo)    if (!isScala) {      clazz.setFlag(sflags)      setPrivateWithin(clazz, jflags)      setPrivateWithin(staticModule, jflags)      if (!hasMeta) {        clazz.setInfo(classInfo)      }      statics.setInfo(staticInfo)      staticModule.setInfo(statics.tpe)      staticModule.setFlag(JAVA)      staticModule.moduleClass.setFlag(JAVA)      in.bp = curbp      val fieldCount = in.nextChar      for (i <- 0 until fieldCount) parseField()      sawPrivateConstructor = false      val methodCount = in.nextChar      for (i <- 0 until methodCount) parseMethod()      if (!sawPrivateConstructor &&          (instanceDefs.lookup(nme.CONSTRUCTOR) == NoSymbol &&           (sflags & INTERFACE) == 0))        {          //Console.println("adding constructor to " + clazz);//DEBUG          instanceDefs.enter(            clazz.newConstructor(NoPosition)            .setFlag(clazz.flags & ConstrFlags)            .setInfo(MethodType(List(), clazz.tpe)))          // If the annotation has an attribute with name 'value'          // add a constructor for it          if (isAnnotation) {            val value = instanceDefs.lookup(nme.value)            if (value != NoSymbol) {              instanceDefs.enter(                clazz.newConstructor(NoPosition)                .setFlag(clazz.flags & ConstrFlags)                .setInfo(MethodType(List(value.tpe.resultType), clazz.tpe)))            }          }        }    }  }  def parseField() {    val jflags = in.nextChar    var sflags = transFlags(jflags)    if ((sflags & FINAL) == 0) sflags = sflags | MUTABLE    if ((sflags & PRIVATE) != 0 && !global.settings.XO.value) {      in.skip(4); skipAttributes()    } else {      val name = pool.getName(in.nextChar)      val info = pool.getType(in.nextChar)      val sym = getOwner(jflags)        .newValue(NoPosition, name).setFlag(sflags)      sym.setInfo(if ((jflags & JAVA_ACC_ENUM) == 0) info else mkConstantType(Constant(sym)))      setPrivateWithin(sym, jflags)      parseAttributes(sym, info)

⌨️ 快捷键说明

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