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