icodereader.scala

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

SCALA
1,047
字号
                case JVM.pop         => code.emit(DROP(INT))   // any 1-word type would do        case JVM.pop2        => code.emit(DROP(LONG))  // any 2-word type would do        case JVM.dup         => code.emit(DUP(OBJECT)) // TODO: Is the kind inside DUP ever needed?        case JVM.dup_x1      => code.emit(DUP_X1)      // Predef.error("Unsupported JVM bytecode: dup_x1")        case JVM.dup_x2      => code.emit(DUP_X2)      // Predef.error("Unsupported JVM bytecode: dup_x2")        case JVM.dup2        => code.emit(DUP(LONG))   // TODO: Is the kind inside DUP ever needed?        case JVM.dup2_x1     => code.emit(DUP2_X1)     // Predef.error("Unsupported JVM bytecode: dup2_x1")        case JVM.dup2_x2     => code.emit(DUP2_X2)     // Predef.error("Unsupported JVM bytecode: dup2_x2")        case JVM.swap        => Predef.error("Unsupported JVM bytecode: swap")        case JVM.iadd        => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))        case JVM.ladd        => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, LONG)))        case JVM.fadd        => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, FLOAT)))        case JVM.dadd        => code.emit(CALL_PRIMITIVE(Arithmetic(ADD, DOUBLE)))        case JVM.isub        => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, INT)))        case JVM.lsub        => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, LONG)))        case JVM.fsub        => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, FLOAT)))        case JVM.dsub        => code.emit(CALL_PRIMITIVE(Arithmetic(SUB, DOUBLE)))        case JVM.imul        => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, INT)))        case JVM.lmul        => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, LONG)))        case JVM.fmul        => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, FLOAT)))        case JVM.dmul        => code.emit(CALL_PRIMITIVE(Arithmetic(MUL, DOUBLE)))        case JVM.idiv        => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, INT)))        case JVM.ldiv        => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, LONG)))        case JVM.fdiv        => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, FLOAT)))        case JVM.ddiv        => code.emit(CALL_PRIMITIVE(Arithmetic(DIV, DOUBLE)))        case JVM.irem        => code.emit(CALL_PRIMITIVE(Arithmetic(REM, INT)))        case JVM.lrem        => code.emit(CALL_PRIMITIVE(Arithmetic(REM, LONG)))        case JVM.frem        => code.emit(CALL_PRIMITIVE(Arithmetic(REM, FLOAT)))        case JVM.drem        => code.emit(CALL_PRIMITIVE(Arithmetic(REM, DOUBLE)))        case JVM.ineg        => code.emit(CALL_PRIMITIVE(Negation(INT)))        case JVM.lneg        => code.emit(CALL_PRIMITIVE(Negation(LONG)))        case JVM.fneg        => code.emit(CALL_PRIMITIVE(Negation(FLOAT)))        case JVM.dneg        => code.emit(CALL_PRIMITIVE(Negation(DOUBLE)))        case JVM.ishl        => code.emit(CALL_PRIMITIVE(Shift(LSL, INT)))        case JVM.lshl        => code.emit(CALL_PRIMITIVE(Shift(LSL, LONG)))        case JVM.ishr        => code.emit(CALL_PRIMITIVE(Shift(LSR, INT)))        case JVM.lshr        => code.emit(CALL_PRIMITIVE(Shift(LSR, LONG)))        case JVM.iushr       => code.emit(CALL_PRIMITIVE(Shift(ASR, INT)))        case JVM.lushr       => code.emit(CALL_PRIMITIVE(Shift(ASR, LONG)))        case JVM.iand        => code.emit(CALL_PRIMITIVE(Logical(AND, INT)))        case JVM.land        => code.emit(CALL_PRIMITIVE(Logical(AND, LONG)))        case JVM.ior         => code.emit(CALL_PRIMITIVE(Logical(OR, INT)))        case JVM.lor         => code.emit(CALL_PRIMITIVE(Logical(OR, LONG)))        case JVM.ixor        => code.emit(CALL_PRIMITIVE(Logical(XOR, INT)))        case JVM.lxor        => code.emit(CALL_PRIMITIVE(Logical(XOR, LONG)))        case JVM.iinc        =>          size += 2          val local = code.getLocal(in.nextByte, INT)          code.emit(LOAD_LOCAL(local))          code.emit(CONSTANT(Constant(in.nextByte)))          code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))          code.emit(STORE_LOCAL(local))        case JVM.i2l         => code.emit(CALL_PRIMITIVE(Conversion(INT, LONG)))        case JVM.i2f         => code.emit(CALL_PRIMITIVE(Conversion(INT, FLOAT)))        case JVM.i2d         => code.emit(CALL_PRIMITIVE(Conversion(INT, DOUBLE)))        case JVM.l2i         => code.emit(CALL_PRIMITIVE(Conversion(LONG, INT)))        case JVM.l2f         => code.emit(CALL_PRIMITIVE(Conversion(LONG, FLOAT)))        case JVM.l2d         => code.emit(CALL_PRIMITIVE(Conversion(LONG, DOUBLE)))        case JVM.f2i         => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, INT)))        case JVM.f2l         => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, LONG)))        case JVM.f2d         => code.emit(CALL_PRIMITIVE(Conversion(FLOAT, DOUBLE)))        case JVM.d2i         => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, INT)))        case JVM.d2l         => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, LONG)))        case JVM.d2f         => code.emit(CALL_PRIMITIVE(Conversion(DOUBLE, FLOAT)))        case JVM.i2b         => code.emit(CALL_PRIMITIVE(Conversion(INT, BYTE)))        case JVM.i2c         => code.emit(CALL_PRIMITIVE(Conversion(INT, CHAR)))        case JVM.i2s         => code.emit(CALL_PRIMITIVE(Conversion(INT, SHORT)))        case JVM.lcmp        => code.emit(CALL_PRIMITIVE(Comparison(CMP, LONG)))        case JVM.fcmpl       => code.emit(CALL_PRIMITIVE(Comparison(CMPL, FLOAT)))        case JVM.fcmpg       => code.emit(CALL_PRIMITIVE(Comparison(CMPG, FLOAT)))        case JVM.dcmpl       => code.emit(CALL_PRIMITIVE(Comparison(CMPL, DOUBLE)))        case JVM.dcmpg       => code.emit(CALL_PRIMITIVE(Comparison(CMPG, DOUBLE)))        case JVM.ifeq        => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, INT))        case JVM.ifne        => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, INT))        case JVM.iflt        => code.emit(LCZJUMP(parseJumpTarget, pc + size, LT, INT))        case JVM.ifge        => code.emit(LCZJUMP(parseJumpTarget, pc + size, GE, INT))        case JVM.ifgt        => code.emit(LCZJUMP(parseJumpTarget, pc + size, GT, INT))        case JVM.ifle        => code.emit(LCZJUMP(parseJumpTarget, pc + size, LE, INT))        case JVM.if_icmpeq   => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, INT))        case JVM.if_icmpne   => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, INT))        case JVM.if_icmplt   => code.emit(LCJUMP(parseJumpTarget, pc + size, LT, INT))        case JVM.if_icmpge   => code.emit(LCJUMP(parseJumpTarget, pc + size, GE, INT))        case JVM.if_icmpgt   => code.emit(LCJUMP(parseJumpTarget, pc + size, GT, INT))        case JVM.if_icmple   => code.emit(LCJUMP(parseJumpTarget, pc + size, LE, INT))        case JVM.if_acmpeq   => code.emit(LCJUMP(parseJumpTarget, pc + size, EQ, OBJECT))        case JVM.if_acmpne   => code.emit(LCJUMP(parseJumpTarget, pc + size, NE, OBJECT))        case JVM.goto        => emit(LJUMP(parseJumpTarget))        case JVM.jsr         => Predef.error("Cannot handle jsr/ret")        case JVM.ret         => Predef.error("Cannot handle jsr/ret")        case JVM.tableswitch =>          val padding = if ((pc + size) % 4 != 0) 4 - ((pc + size) % 4) else 0          size += padding          in.bp += padding          assert((pc + size % 4) != 0)/*          var byte1 = in.nextByte; size += 1;          while (byte1 == 0) { byte1 = in.nextByte; size += 1; }          val default = byte1 << 24 | in.nextByte << 16 | in.nextByte << 8 | in.nextByte;          size = size + 3       */          val default = pc + in.nextInt; size += 4          val low  = in.nextInt          val high = in.nextInt          size += 8          assert(low <= high, "Value low not <= high for tableswitch.")          val tags = List.tabulate(high - low + 1, n => List(low + n))          val targets = for (_ <- tags) yield parseJumpTargetW          code.emit(LSWITCH(tags, targets ::: List(default)))        case JVM.lookupswitch =>          val padding = if ((pc + size) % 4 != 0) 4 - ((pc + size) % 4) else 0          size += padding          in.bp += padding          assert((pc + size % 4) != 0)          val default = pc + in.nextInt; size += 4          val npairs = in.nextInt; size += 4          var tags: List[List[Int]] = Nil          var targets: List[Int] = Nil          var i = 0          while (i < npairs) {            tags = List(in.nextInt) :: tags; size += 4            targets = parseJumpTargetW :: targets; // parseJumpTargetW updates 'size' itself            i += 1          }          targets = default :: targets          code.emit(LSWITCH(tags.reverse, targets.reverse))        case JVM.ireturn     => code.emit(RETURN(INT))        case JVM.lreturn     => code.emit(RETURN(LONG))        case JVM.freturn     => code.emit(RETURN(FLOAT))        case JVM.dreturn     => code.emit(RETURN(DOUBLE))        case JVM.areturn     => code.emit(RETURN(OBJECT))        case JVM.return_     => code.emit(RETURN(UNIT))        case JVM.getstatic    =>          val field = pool.getMemberSymbol(in.nextChar, true); size += 2          if (field.hasFlag(Flags.MODULE))            code.emit(LOAD_MODULE(field))          else            code.emit(LOAD_FIELD(field, true))        case JVM.putstatic   =>          val field = pool.getMemberSymbol(in.nextChar, true); size += 2          code.emit(STORE_FIELD(field, true))        case JVM.getfield    =>          val field = pool.getMemberSymbol(in.nextChar, false); size += 2          code.emit(LOAD_FIELD(field, false))        case JVM.putfield    =>          val field = pool.getMemberSymbol(in.nextChar, false); size += 2          code.emit(STORE_FIELD(field, false))        case JVM.invokevirtual =>          val m = pool.getMemberSymbol(in.nextChar, false); size += 2          code.emit(CALL_METHOD(m, Dynamic))        case JVM.invokeinterface  =>          val m = pool.getMemberSymbol(in.nextChar, false); size += 4          in.skip(2)          code.emit(CALL_METHOD(m, Dynamic))        case JVM.invokespecial   =>          val m = pool.getMemberSymbol(in.nextChar, false); size += 2          val style = if (m.name == nme.CONSTRUCTOR || m.hasFlag(Flags.PRIVATE)) Static(true)                       else SuperCall(m.owner.name);          code.emit(CALL_METHOD(m, style))        case JVM.invokestatic    =>          val m = pool.getMemberSymbol(in.nextChar, true); size += 2          if (isBox(m))            code.emit(BOX(toTypeKind(m.info.paramTypes.head)))          else if (isUnbox(m))            code.emit(UNBOX(toTypeKind(m.info.resultType)))          else            code.emit(CALL_METHOD(m, Static(false)))        case JVM.new_          =>          code.emit(NEW(REFERENCE(pool.getClassSymbol(in.nextChar))))          size += 2        case JVM.newarray      =>          val kind = in.nextByte match {            case T_BOOLEAN => BOOL            case T_CHAR    => CHAR            case T_FLOAT   => FLOAT            case T_DOUBLE  => DOUBLE            case T_BYTE    => BYTE            case T_SHORT   => SHORT            case T_INT     => INT            case T_LONG    => LONG          }          size += 1          code.emit(CREATE_ARRAY(kind, 1))        case JVM.anewarray     =>          val tpe = pool.getClassOrArrayType(in.nextChar); size += 2          code.emit(CREATE_ARRAY(toTypeKind(tpe), 1))        case JVM.arraylength   => code.emit(CALL_PRIMITIVE(ArrayLength(OBJECT))); // the kind does not matter        case JVM.athrow        => code.emit(THROW());        case JVM.checkcast     =>          code.emit(CHECK_CAST(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size += 2        case JVM.instanceof    =>          code.emit(IS_INSTANCE(toTypeKind(pool.getClassOrArrayType(in.nextChar)))); size += 2        case JVM.monitorenter  => code.emit(MONITOR_ENTER())        case JVM.monitorexit   => code.emit(MONITOR_EXIT())        case JVM.wide          =>          size += 1          toUnsignedByte(in.nextByte) match {            case JVM.iload  => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, INT)));    size += 2            case JVM.lload  => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, LONG)));   size += 2            case JVM.fload  => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, FLOAT)));  size += 2            case JVM.dload  => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, DOUBLE))); size += 2            case JVM.aload  => code.emit(LOAD_LOCAL(code.getLocal(in.nextChar, OBJECT))); size += 2            case JVM.istore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, INT)));    size += 2            case JVM.lstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, LONG)));   size += 2            case JVM.fstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, FLOAT)));  size += 2            case JVM.dstore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, DOUBLE))); size += 2            case JVM.astore => code.emit(STORE_LOCAL(code.getLocal(in.nextChar, OBJECT))); size += 2            case JVM.ret => Predef.error("Cannot handle jsr/ret")            case JVM.iinc =>              size += 4              val local = code.getLocal(in.nextChar, INT)              code.emit(CONSTANT(Constant(in.nextChar)))              code.emit(CALL_PRIMITIVE(Arithmetic(ADD, INT)))              code.emit(STORE_LOCAL(local))            case _ => Predef.error("Invalid 'wide' operand")          }        case JVM.multianewarray =>          size += 3          val tpe = toTypeKind(pool.getClassOrArrayType(in.nextChar))          val dim = in.nextByte//          assert(dim == 1, "Cannot handle multidimensional arrays yet.")          code.emit(CREATE_ARRAY(tpe, dim))        case JVM.ifnull    => code.emit(LCZJUMP(parseJumpTarget, pc + size, EQ, OBJECT))        case JVM.ifnonnull => code.emit(LCZJUMP(parseJumpTarget, pc + size, NE, OBJECT))        case JVM.goto_w    => code.emit(LJUMP(parseJumpTargetW))        case JVM.jsr_w     => Predef.error("Cannot handle jsr/ret")//        case _ => Predef.error("Unknown bytecode")      }      pc += size    }    // add parameters    var idx = if (method.isStatic) 0 else 1    for (t <- method.symbol.tpe.paramTypes) {      this.method.addParam(code.enterParam(idx, toTypeKind(t)))      idx += 1    }        pc = 0    while (pc < codeLength) parseInstruction    val exceptionEntries = in.nextChar.toInt    var i = 0    while (i < exceptionEntries) {      // skip start end PC      in.skip(4)      // read the handler PC      code.jmpTargets += in.nextChar      // skip the exception type      in.skip(2)      i += 1    }    skipAttributes()    code.toBasicBlock    assert(method.code ne null)    // reverse parameters, as they were prepended during code generation    method.params = method.params.reverse    if (code.containsDUPX) {            code.resolveDups    }    if (code.containsNEW) code.resolveNEWs  }  /** TODO: move in Definitions and remove obsolete isBox/isUnbox found there. */  def isBox(m: Symbol): Boolean =     (m.owner == definitions.BoxesRunTimeClass.moduleClass        && m.name.startsWith("boxTo"))  def isUnbox(m: Symbol): Boolean =     (m.owner == definitions.BoxesRunTimeClass.moduleClass        && m.name.startsWith("unboxTo"))    /** Return the icode class that should include members with the given flags.   *  There are two possible classes, the static part and the instance part.   */  def getCode(flags: Int): IClass =    if ((flags & JAVA_ACC_STATIC) != 0) staticCode else instanceCode  class LinearCode {    var instrs: ListBuffer[(Int, Instruction)] = new ListBuffer    var jmpTargets: Set[Int] = new HashSet[Int]    var locals: Map[Int, List[(Local, TypeKind)]] = new HashMap()    var containsDUPX = false    var containsNEW  = false        def emit(i: Instruction) {       instrs += (pc, i)      if (i.isInstanceOf[DupX])        containsDUPX = true      if (i.isInstanceOf[opcodes.NEW])        containsNEW = true    }    /** Break this linear code in basic block representation     *  As a side effect, it sets the 'code' field of the current     */    def toBasicBlock: Code = {      import opcodes._            val code = new Code(method.symbol.name.toString, method);      method.setCode(code)      var bb = code.startBlock      def makeBasicBlocks: Map[Int, BasicBlock] = {        val block: Map[Int, BasicBlock] = new HashMap        for (pc <- jmpTargets) block += (pc -> code.newBlock)        block      }      val blocks = makeBasicBlocks      var otherBlock: BasicBlock = null      var disableJmpTarget = false            for ((pc, instr) <- instrs.elements) {//        Console.println("> " + pc + ": " + instr);        if (jmpTargets contains pc) {          otherBlock = blocks(pc)          if (!bb.isClosed && otherBlock != bb) {            bb.emit(JUMP(otherBlock))            bb.close//            Console.println("\t> closing bb: " + bb)          }          bb = otherBlock//          Console.println("\t> entering bb: " + bb)        }        instr match {          case LJUMP(target) =>             otherBlock = blocks(target)            bb.emit(JUMP(otherBlock))            bb.close

⌨️ 快捷键说明

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