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