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 + -
显示快捷键?