📄 constantanalyzer.java
字号:
ConstValue[] argValues = new ConstValue[paramTypes.length]; for (int i = paramTypes.length - 1; i >= 0; i--) { size += TypeSignature.getTypeSize(paramTypes[i]); Object value = (argValues[i] = info.getStack(size)).value; if (value != ConstValue.VOLATILE) args[i] = value; else constant = false; } if (opcode != opc_invokestatic) { size++; clsValue = info.getStack(size); cls = clsValue.value; if (cls == ConstValue.VOLATILE || cls == null) constant = false; } String retType = TypeSignature.getReturnType(ref.getType()); if (retType.equals("V")) { handleReference(ref, opcode == opc_invokevirtual || opcode == opc_invokeinterface); mergeInfo(instr.getNextByAddr(), info.pop(size)); break; } if (constant && !runtime.isWhite(retType)) { /* This is not a valid constant type */ constant = false; } Object methodResult = null; if (constant) { try { methodResult = runtime.invokeMethod (ref, opcode != opc_invokespecial, cls, args); } catch (InterpreterException ex) { constant = false; if (jode.GlobalOptions.verboseLevel > 3) GlobalOptions.err.println("Can't interpret "+ref+": " + ex.getMessage()); /* result is not constant */ } catch (InvocationTargetException ex) { constant = false; if (jode.GlobalOptions.verboseLevel > 3) GlobalOptions.err.println("Method "+ref +" throwed exception: " + ex.getTargetException()); /* method always throws exception ? */ } } ConstValue returnVal; if (!constant) { handleReference(ref, opcode == opc_invokevirtual || opcode == opc_invokeinterface); int retsize = TypeSignature.getTypeSize(retType); returnVal = unknownValue[retsize - 1]; } else { info.constInfo = new ConstantInfo(CONSTANT, methodResult); returnVal = new ConstValue(methodResult); returnVal.addConstantListener(info.constInfo); if (clsValue != null) clsValue.addConstantListener(returnVal); for (int i=0; i< argValues.length; i++) argValues[i].addConstantListener(returnVal); } mergeInfo(instr.getNextByAddr(), info.poppush(size, returnVal)); break; } case opc_new: { handleClass(instr.getClazzType()); mergeInfo(instr.getNextByAddr(), info.poppush(0, unknownValue[0])); break; } case opc_arraylength: {// ConstValue array = info.getStack(1);// if (array.value != ConstValue.VOLATILE// && array.value != null) {// Integer newValue = new Integer(Array.getLength(array.value));// info.constInfo = new ConstantInfo(CONSTANT, newValue);// result = new ConstValue(newValue);// result.addConstantListener(info.constInfo);// array.addConstantListener(result);// } else result = unknownValue[0]; mergeInfo(instr.getNextByAddr(), info.poppush(1, result)); break; } case opc_checkcast: { handleClass(instr.getClazzType()); mergeInfo(instr.getNextByAddr(), info.pop(0)); break; } case opc_instanceof: { handleClass(instr.getClazzType()); mergeInfo(instr.getNextByAddr(), info.poppush(1, unknownValue[0])); break; } case opc_monitorenter: case opc_monitorexit: mergeInfo(instr.getNextByAddr(), info.pop(1)); break; case opc_multianewarray: handleClass(instr.getClazzType()); mergeInfo(instr.getNextByAddr(), info.poppush(instr.getDimensions(), unknownValue[0])); break; default: throw new IllegalArgumentException("Invalid opcode "+opcode); } } public void fieldNotConstant(FieldIdentifier fi) { for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); if (instr.getOpcode() == opc_getfield || instr.getOpcode() == opc_getstatic) { Reference ref = instr.getReference(); if (ref.getName().equals(fi.getName()) && ref.getType().equals(fi.getType()) && instr.getTmpInfo() != null) { ((StackLocalInfo) instr.getTmpInfo()).enqueue(); } } } } public void dumpStackLocalInfo() { for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); System.err.println(""+instr.getTmpInfo()); System.err.println(instr.getDescription()); } } public void analyzeCode(MethodIdentifier methodIdent, BytecodeInfo bytecode) { this.bytecode = bytecode; TodoQueue modifiedQueue = new TodoQueue(); MethodInfo minfo = bytecode.getMethodInfo(); for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); instr.setTmpInfo(null); } StackLocalInfo firstInfo = new StackLocalInfo (bytecode.getMaxLocals(), minfo.isStatic(), minfo.getType(), modifiedQueue); firstInfo.instr = (Instruction) bytecode.getInstructions().get(0); firstInfo.instr.setTmpInfo(firstInfo); firstInfo.enqueue(); runtime.setFieldListener(methodIdent); while (modifiedQueue.first != null) { StackLocalInfo info = modifiedQueue.first; modifiedQueue.first = info.nextOnQueue; info.nextOnQueue = null; handleOpcode(info, methodIdent); } runtime.setFieldListener(null); Handler[] handlers = bytecode.getExceptionHandlers(); for (int i=0; i< handlers.length; i++) { if (handlers[i].catcher.getTmpInfo() != null && handlers[i].type != null) Main.getClassBundle().reachableClass(handlers[i].type); } for (Iterator iter = bytecode.getInstructions().iterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); StackLocalInfo info = (StackLocalInfo) instr.getTmpInfo(); if (info != null) { if (info.constInfo.flags == 0) instr.setTmpInfo(unknownConstInfo); else instr.setTmpInfo(info.constInfo); } } } public static void replaceWith(ListIterator iter, Instruction instr, Instruction replacement) { switch(instr.getOpcode()) { case opc_goto: case opc_ldc: case opc_ldc2_w: case opc_iload: case opc_lload: case opc_fload: case opc_dload: case opc_aload: case opc_getstatic: if (replacement == null) iter.remove(); else iter.set(replacement); return; case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: case opc_ifnull: case opc_ifnonnull: case opc_arraylength: case opc_getfield: case opc_i2l: case opc_i2f: case opc_i2d: case opc_f2i: case opc_f2l: case opc_f2d: case opc_i2b: case opc_i2c: case opc_i2s: case opc_ineg: case opc_fneg: iter.set(new Instruction(opc_pop)); break; case opc_lcmp: case opc_dcmpg: case opc_dcmpl: case opc_ladd: case opc_dadd: case opc_lsub: case opc_dsub: case opc_lmul: case opc_dmul: case opc_ldiv: case opc_ddiv: case opc_lrem: case opc_drem: case opc_land: case opc_lor : case opc_lxor: iter.set(new Instruction(opc_pop2)); iter.add(new Instruction(opc_pop2)); break; case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: case opc_fcmpg: case opc_fcmpl: case opc_l2i: case opc_l2f: case opc_l2d: case opc_d2i: case opc_d2l: case opc_d2f: case opc_lneg: case opc_dneg: case opc_iadd: case opc_fadd: case opc_isub: case opc_fsub: case opc_imul: case opc_fmul: case opc_idiv: case opc_fdiv: case opc_irem: case opc_frem: case opc_iand: case opc_ior : case opc_ixor: case opc_ishl: case opc_ishr: case opc_iushr: case opc_iaload: case opc_laload: case opc_faload: case opc_daload: case opc_aaload: case opc_baload: case opc_caload: case opc_saload: iter.set(new Instruction(opc_pop2)); break; case opc_lshl: case opc_lshr: case opc_lushr: iter.set(new Instruction(opc_pop)); iter.add(new Instruction(opc_pop2)); break; case opc_putstatic: case opc_putfield: if (TypeSignature .getTypeSize(instr.getReference().getType()) == 2) { iter.set(new Instruction(opc_pop2)); if (instr.getOpcode() == opc_putfield) iter.add(new Instruction(opc_pop)); } else iter.set(new Instruction(instr.getOpcode() == opc_putfield ? opc_pop2 : opc_pop)); break; case opc_invokespecial: case opc_invokestatic: case opc_invokeinterface: case opc_invokevirtual: { Reference ref = instr.getReference(); String[] pt = TypeSignature.getParameterTypes(ref.getType()); int len = pt.length; if (len > 0) { iter.set(new Instruction(TypeSignature.getTypeSize(pt[--len]) + opc_pop - 1)); for (int i = len - 1; i >= 0; i--) iter.add(new Instruction(TypeSignature.getTypeSize(pt[i]) + opc_pop - 1)); if (instr.getOpcode() != opc_invokestatic) iter.add(new Instruction(opc_pop)); } else if (instr.getOpcode() != opc_invokestatic) { iter.set(new Instruction(opc_pop)); } else { if (replacement == null) iter.remove(); else iter.set(replacement); return; } } } if (replacement != null) iter.add(replacement); } public void appendJump(ListIterator iter, Instruction dest) { /* Add a goto instruction after this opcode. */ Instruction gotoInstr = new Instruction(Instruction.opc_goto); gotoInstr.setSuccs(dest); iter.add(gotoInstr); } public void transformCode(BytecodeInfo bytecode) { for (ListIterator iter = bytecode.getInstructions().listIterator(); iter.hasNext(); ) { Instruction instr = (Instruction) iter.next(); ConstantInfo info = (ConstantInfo) instr.getTmpInfo(); instr.setTmpInfo(null); if (info == null || (info.flags & (RETURNINGJSR | RETASTORE)) == RETASTORE) { /* This instruction can't be reached logically, or * it is a return value astore, that should be removed */ iter.remove(); } else if ((info.flags & CONSTANT) != 0) { if (instr.getOpcode() > opc_ldc2_w) { Instruction ldcInstr = new Instruction(info.constant instanceof Long || info.constant instanceof Double ? opc_ldc2_w : opc_ldc); ldcInstr.setConstant(info.constant); replaceWith(iter, instr, ldcInstr); if (GlobalOptions.verboseLevel > 2) GlobalOptions.err.println (bytecode + ": Replacing " + instr + " with constant " + info.constant); } } else if ((info.flags & CONSTANTFLOW) != 0) { Instruction pc = (Instruction) info.constant; if (instr.getOpcode() >= opc_if_icmpeq && instr.getOpcode() <= opc_if_acmpne) iter.set(new Instruction(opc_pop2)); else iter.set(new Instruction(opc_pop)); if (GlobalOptions.verboseLevel > 2) GlobalOptions.err.println (bytecode + ": Replacing " + instr + " with goto " + pc.getAddr()); while (iter.hasNext()) { ConstantInfo nextinfo = (ConstantInfo) ((Instruction) iter.next()).getTmpInfo(); if (nextinfo != null) { Instruction nextInstr = (Instruction) iter.previous(); if (pc != nextInstr) appendJump(iter, pc); break; } /* Next instruction can't be reached logically */ iter.remove(); } } else { int opcode = instr.getOpcode(); switch (opcode) { case opc_nop: iter.remove(); break; case opc_jsr: ConstantInfo jsrinfo = (ConstantInfo) instr.getSingleSucc().getTmpInfo(); if ((jsrinfo.flags & RETURNINGJSR) != 0) /* A normal jsr, don't change it */ break; /* This means, the jsr will never return. We * replace it with a goto, the jsr will transform * itself to remove the astore operation. */ Instruction gotoInstr = new Instruction(opc_goto); gotoInstr.setSuccs(instr.getSingleSucc()); iter.set(gotoInstr); /* fall through */ case opc_goto: case opc_ifeq: case opc_ifne: case opc_iflt: case opc_ifge: case opc_ifgt: case opc_ifle: case opc_ifnull: case opc_ifnonnull: case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: case opc_if_icmpge: case opc_if_icmpgt: case opc_if_icmple: case opc_if_acmpeq: case opc_if_acmpne: while (iter.hasNext()) { ConstantInfo nextinfo = (ConstantInfo) ((Instruction) iter.next()).getTmpInfo(); if (nextinfo != null && ((nextinfo.flags & (RETURNINGJSR | RETASTORE)) != RETASTORE)) { Instruction nextInstr = (Instruction) iter.previous(); if (instr.getSingleSucc() == nextInstr) { /* put iter in sane state */ iter.previous(); iter.next(); replaceWith(iter, instr, null); } break; } /* Next instruction can be removed */ iter.remove(); } break; case opc_putstatic: case opc_putfield: { Reference ref = instr.getReference(); FieldIdentifier fi = (FieldIdentifier) Main.getClassBundle().getIdentifier(ref); if (fi != null && (Main.stripping & Main.STRIP_UNREACH) != 0 && !fi.isReachable()) { replaceWith(iter, instr, null); } break; } } } } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -