📄 constantanalyzer.java
字号:
/* ConstantAnalyzer Copyright (C) 1999-2002 Jochen Hoenicke. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ConstantAnalyzer.java.in,v 1.3.2.6 2002/05/28 17:34:16 hoenicke Exp $ */package jode.obfuscator.modules;import jode.AssertError;import jode.GlobalOptions;import jode.bytecode.*;import jode.jvm.InterpreterException;import jode.obfuscator.*;import java.lang.reflect.Array;import java.lang.reflect.Modifier;import java.lang.reflect.InvocationTargetException;import java.util.BitSet;import java.util.Arrays;import java.util.Collection;import java.util.HashSet;import java.util.Set;import java.util.HashMap;import java.util.Map;import java.util.Iterator;import java.util.ListIterator;/** * Analyze the code, assuming every field that is not yet written to * is constant. This may imply that some code is dead code. * * @author Jochen Hoenicke */public class ConstantAnalyzer extends SimpleAnalyzer implements Opcodes, CodeAnalyzer { BytecodeInfo bytecode; private static ConstantRuntimeEnvironment runtime = new ConstantRuntimeEnvironment(); private final static int CMP_EQ = 0; private final static int CMP_NE = 1; private final static int CMP_LT = 2; private final static int CMP_GE = 3; private final static int CMP_GT = 4; private final static int CMP_LE = 5; private final static int CMP_GREATER_MASK = (1 << CMP_GT)|(1 << CMP_GE)|(1 << CMP_NE); private final static int CMP_LESS_MASK = (1 << CMP_LT)|(1 << CMP_LE)|(1 << CMP_NE); private final static int CMP_EQUAL_MASK = (1 << CMP_GE)|(1 << CMP_LE)|(1 << CMP_EQ); final static int CONSTANT = 0x02; final static int CONSTANTFLOW = 0x04; final static int RETASTORE = 0x08; final static int RETURNINGJSR = 0x10; private interface ConstantListener { public void constantChanged(); } private final static class JSRTargetInfo implements Cloneable { Instruction jsrTarget; BitSet usedLocals; /** * The dependent entries, that want to know if the bit set changed. * This is either a StackLocalInfo (the ret info) or a single * JSRTargetInfo or a Collection of JSRTargetInfos. */ Object dependent; public JSRTargetInfo(Instruction target) { jsrTarget = target; usedLocals = new BitSet(); } public JSRTargetInfo copy() { try { JSRTargetInfo result = (JSRTargetInfo) clone(); result.usedLocals = (BitSet) usedLocals.clone(); addDependent(result); return result; } catch (CloneNotSupportedException ex) { throw new IncompatibleClassChangeError(ex.getMessage()); } } private void addDependent(JSRTargetInfo result) { if (dependent == null || dependent == result) dependent = result; else if (dependent instanceof JSRTargetInfo) { Set newDeps = new HashSet(); newDeps.add(dependent); newDeps.add(result); } else if (dependent instanceof Collection) { ((Collection) dependent).add(result); } } public void setRetInfo(StackLocalInfo retInfo) { dependent = retInfo; } public boolean uses(int localSlot) { return usedLocals.get(localSlot); } public void addUsed(int localSlot) { if (usedLocals.get(localSlot)) return; usedLocals.set(localSlot); if (dependent instanceof StackLocalInfo) ((StackLocalInfo) dependent).enqueue(); else if (dependent instanceof JSRTargetInfo) ((JSRTargetInfo) dependent).addUsed(localSlot); else if (dependent instanceof Collection) { Iterator iter = ((Collection) dependent).iterator(); while (iter.hasNext()) { JSRTargetInfo dep = (JSRTargetInfo) iter.next(); dep.addUsed(localSlot); } } } public void merge(JSRTargetInfo o) { o.addDependent(this); for (int slot = 0; slot < o.usedLocals.size(); slot++) { if (o.usedLocals.get(slot)) addUsed(slot); } } public String toString() { StringBuffer sb = new StringBuffer(String.valueOf(jsrTarget)); if (dependent instanceof StackLocalInfo) sb.append("->").append(((StackLocalInfo) dependent).instr); return sb.append(usedLocals) .append('_').append(hashCode()).toString(); } } private static class ConstValue implements ConstantListener { public final static Object VOLATILE = new Object(); /** * The constant value, VOLATILE if value is not constant. * This may also be an instance of JSRTargetInfo */ Object value; /** * The number of slots this value takes on the stack. */ int stackSize; /** * The constant listeners, that want to be informed if this is * no longer constant. */ Set listeners; public ConstValue(Object constant) { value = constant; stackSize = (constant instanceof Double || constant instanceof Long) ? 2 : 1; listeners = new HashSet(); } public ConstValue(ConstValue constant) { value = constant.value; stackSize = constant.stackSize; listeners = new HashSet(); constant.addConstantListener(this); } public ConstValue(int stackSize) { this.value = VOLATILE; this.stackSize = stackSize; } public ConstValue copy() { return (value == VOLATILE) ? this : new ConstValue(this); } public void addConstantListener(ConstantListener l) { listeners.add(l); } public void removeConstantListener(ConstantListener l) { listeners.remove(l); } public void fireChanged() { value = VOLATILE; for (Iterator i = listeners.iterator(); i.hasNext(); ) ((ConstantListener) i.next()).constantChanged(); listeners = null; } public void constantChanged() { if (value != VOLATILE) fireChanged(); } /** * Merge the other value into this value. */ public void merge(ConstValue other) { if (this == other) return; if (value == null ? other.value == null : value.equals(other.value)) { if (value != VOLATILE) { other.addConstantListener(this); this.addConstantListener(other); } return; } if (value instanceof JSRTargetInfo && other.value instanceof JSRTargetInfo && (((JSRTargetInfo) value).jsrTarget == ((JSRTargetInfo) other.value).jsrTarget)) { ((JSRTargetInfo) value).merge((JSRTargetInfo) other.value); return; } if (value != VOLATILE) fireChanged();// if (other.value != VOLATILE)// other.fireChanged(); } public String toString() { return value == VOLATILE ? "vol("+stackSize+")" : ""+value; } } private static class TodoQueue { StackLocalInfo first; } private static class StackLocalInfo implements ConstantListener { ConstValue[] stack; ConstValue[] locals; Instruction instr; ConstantInfo constInfo; StackLocalInfo retInfo; StackLocalInfo nextOnQueue; /** * The queue that should be notified, if the constant values of * this instruction changes. We put ourself on this queue in that * case. */ TodoQueue notifyQueue; public ConstValue copy(ConstValue value) { return (value == null) ? null : value.copy(); } private StackLocalInfo(ConstValue[] stack, ConstValue[] locals, TodoQueue notifyQueue) { this.stack = stack; this.locals = new ConstValue[locals.length]; for (int i=0; i< locals.length; i++) this.locals[i] = copy(locals[i]); this.notifyQueue = notifyQueue; } public StackLocalInfo(int numLocals, boolean isStatic, String methodTypeSig, TodoQueue notifyQueue) { String[] paramTypes = TypeSignature.getParameterTypes(methodTypeSig); locals = new ConstValue[numLocals]; stack = new ConstValue[0]; this.notifyQueue = notifyQueue; int slot = 0; if (!isStatic) locals[slot++] = new ConstValue(1); for (int i=0; i< paramTypes.length; i++) { int stackSize = TypeSignature.getTypeSize(paramTypes[i]); locals[slot] = unknownValue[stackSize-1]; slot += stackSize; } } public final void enqueue() { if (nextOnQueue == null) { this.nextOnQueue = notifyQueue.first; notifyQueue.first = this; } } public void constantChanged() { enqueue(); } public StackLocalInfo poppush(int pops, ConstValue push) { ConstValue[] newStack = new ConstValue[stack.length - pops + push.stackSize]; ConstValue[] newLocals = (ConstValue[]) locals.clone(); System.arraycopy(stack, 0, newStack, 0, stack.length-pops); newStack[stack.length-pops] = push.copy(); return new StackLocalInfo(newStack, newLocals, notifyQueue); } public StackLocalInfo pop(int pops) { ConstValue[] newStack = new ConstValue[stack.length - pops]; ConstValue[] newLocals = (ConstValue[]) locals.clone(); System.arraycopy(stack, 0, newStack, 0, stack.length-pops); return new StackLocalInfo(newStack, newLocals, notifyQueue); } public StackLocalInfo dup(int count, int depth) { ConstValue[] newStack = new ConstValue[stack.length + count]; ConstValue[] newLocals = (ConstValue[]) locals.clone(); if (depth == 0) System.arraycopy(stack, 0, newStack, 0, stack.length); else { int pos = stack.length - count - depth; System.arraycopy(stack, 0, newStack, 0, pos); for (int i=0; i < count; i++) newStack[pos++] = copy(stack[stack.length-count + i]); for (int i=0; i < depth; i++) newStack[pos++] = copy(stack[stack.length-count-depth + i]); } for (int i=0; i < count; i++) newStack[stack.length+i] = copy(stack[stack.length-count + i]); return new StackLocalInfo(newStack, newLocals, notifyQueue); } public StackLocalInfo swap() { ConstValue[] newStack = new ConstValue[stack.length]; ConstValue[] newLocals = (ConstValue[]) locals.clone(); System.arraycopy(stack, 0, newStack, 0, stack.length - 2); newStack[stack.length-2] = stack[stack.length-1].copy(); newStack[stack.length-1] = stack[stack.length-2].copy(); return new StackLocalInfo(newStack, newLocals, notifyQueue); } public StackLocalInfo copy() { ConstValue[] newStack = (ConstValue[]) stack.clone(); ConstValue[] newLocals = (ConstValue[]) locals.clone(); return new StackLocalInfo(newStack, newLocals, notifyQueue); } public ConstValue getLocal(int slot) { return locals[slot]; } public ConstValue getStack(int depth) { return stack[stack.length - depth]; } public StackLocalInfo setLocal(int slot, ConstValue value) { locals[slot] = value; if (value != null && value.stackSize == 2) locals[slot+1] = null; for (int i=0; i< locals.length; i++) { if (locals[i] != null && locals[i].value instanceof JSRTargetInfo) { JSRTargetInfo jsrInfo = (JSRTargetInfo)locals[i].value; if (!jsrInfo.uses(slot)) { jsrInfo = jsrInfo.copy(); locals[i] = locals[i].copy(); locals[i].value = jsrInfo; jsrInfo.addUsed(slot); } } } for (int i=0; i< stack.length; i++) { if (stack[i] != null && stack[i].value instanceof JSRTargetInfo) { JSRTargetInfo jsrInfo = (JSRTargetInfo)stack[i].value; if (!jsrInfo.uses(slot)) { jsrInfo = jsrInfo.copy(); stack[i] = stack[i].copy(); stack[i].value = jsrInfo; jsrInfo.addUsed(slot); } } } return this; } public StackLocalInfo mergeRetLocals(JSRTargetInfo jsrTargetInfo, StackLocalInfo retInfo) { for (int slot = 0; slot < locals.length; slot++) { if (jsrTargetInfo.uses(slot)) locals[slot] = retInfo.locals[slot]; } locals[retInfo.instr.getLocalSlot()] = null;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -