diff options
Diffstat (limited to 'third_party/java/proguard/proguard5.3.3/src/proguard/evaluation/Variables.java')
-rw-r--r-- | third_party/java/proguard/proguard5.3.3/src/proguard/evaluation/Variables.java | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/third_party/java/proguard/proguard5.3.3/src/proguard/evaluation/Variables.java b/third_party/java/proguard/proguard5.3.3/src/proguard/evaluation/Variables.java new file mode 100644 index 0000000000..d61364a793 --- /dev/null +++ b/third_party/java/proguard/proguard5.3.3/src/proguard/evaluation/Variables.java @@ -0,0 +1,347 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare + * + * 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 of the License, 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; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package proguard.evaluation; + +import proguard.evaluation.value.*; + +import java.util.Arrays; + +/** + * This class represents a local variable frame that contains <code>Value</code> + * objects. Values are generalizations of all values that have been stored in + * the respective variables. + * + * @author Eric Lafortune + */ +public class Variables +{ + private static final TopValue TOP_VALUE = new TopValue(); + + + protected Value[] values; + protected int size; + + + /** + * Creates a new Variables object with a given maximum number of variables. + */ + public Variables(int size) + { + this.values = new Value[size]; + this.size = size; + } + + + /** + * Creates a Variables object that is a copy of the given Variables object. + */ + public Variables(Variables variables) + { + // Create the values array. + this(variables.size); + + // Copy the values. + initialize(variables); + } + + + /** + * Resets this Variables object, so that it can be reused. + */ + public void reset(int size) + { + // Is the values array large enough? + if (values.length < size) + { + // Create a new one. + values = new Value[size]; + } + else + { + // Clear the old variables. + Arrays.fill(values, 0, this.size, null); + } + + this.size = size; + } + + + /** + * Initializes the values of this Variables object with the values of the + * given Variables object. The other object may have fewer values, in which + * case the remaining values are left unchanged. + */ + public void initialize(Variables other) + { + if (this.size < other.size) + { + throw new IllegalArgumentException("Variable frame is too small ["+this.size+"] compared to other frame ["+other.size+"]"); + } + + // Copy the values. + System.arraycopy(other.values, 0, this.values, 0, other.size); + } + + + /** + * Generalizes the values of this Variables object with the values of the + * given Variables object. + * @param clearConflictingOtherVariables specifies whether the other + * variables should be cleared too, + * in case of conflicts. + * @return whether the generalization has made any difference. + */ + public boolean generalize(Variables other, + boolean clearConflictingOtherVariables) + { + if (this.size != other.size) + { + throw new IllegalArgumentException("Variable frames have different sizes ["+this.size+"] and ["+other.size+"]"); + } + + boolean changed = false; + + for (int index = 0; index < size; index++) + { + Value thisValue = this.values[index]; + Value otherValue = other.values[index]; + + // Occasionally, two values of different types might be present + // in the same variable in a variable frame (corresponding to + // two local variables that share the same index), at some point + // outside of their scopes. Don't generalize the variable then, + // but let it clear instead. + if (thisValue != null && + otherValue != null && + thisValue.computationalType() == otherValue.computationalType()) + { + Value newValue = thisValue.generalize(otherValue); + + changed = changed || !thisValue.equals(newValue); + + this.values[index] = newValue; + } + else + { + changed = changed || thisValue != null; + + this.values[index] = null; + + if (clearConflictingOtherVariables) + { + other.values[index] = null; + } + } + } + + return changed; + } + + + /** + * Returns the number of variables. + */ + public int size() + { + return size; + } + + + /** + * Gets the Value of the variable with the given index, without disturbing it. + */ + public Value getValue(int index) + { + if (index < 0 || + index >= size) + { + throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); + } + + return values[index]; + } + + + /** + * Stores the given Value at the given variable index. + */ + public void store(int index, Value value) + { + if (index < 0 || + index >= size) + { + throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); + } + + // Store the value. + values[index] = value; + + // Account for the extra space required by Category 2 values. + if (value.isCategory2()) + { + values[index + 1] = TOP_VALUE; + } + } + + + /** + * Loads the Value from the variable with the given index. + */ + public Value load(int index) + { + if (index < 0 || + index >= size) + { + throw new IndexOutOfBoundsException("Variable index ["+index+"] out of bounds ["+size+"]"); + } + + return values[index]; + } + + + // Load methods that provide convenient casts to the expected value types. + + /** + * Loads the IntegerValue from the variable with the given index. + */ + public IntegerValue iload(int index) + { + return load(index).integerValue(); + } + + + /** + * Loads the LongValue from the variable with the given index. + */ + public LongValue lload(int index) + { + return load(index).longValue(); + } + + + /** + * Loads the FloatValue from the variable with the given index. + */ + public FloatValue fload(int index) + { + return load(index).floatValue(); + } + + + /** + * Loads the DoubleValue from the variable with the given index. + */ + public DoubleValue dload(int index) + { + return load(index).doubleValue(); + } + + + /** + * Loads the ReferenceValue from the variable with the given index. + */ + public ReferenceValue aload(int index) + { + return load(index).referenceValue(); + } + + + /** + * Loads the InstructionOffsetValue from the variable with the given index. + */ + public InstructionOffsetValue oload(int index) + { + return load(index).instructionOffsetValue(); + } + + + // Implementations for Object. + + public boolean equals(Object object) + { + if (object == null || + this.getClass() != object.getClass()) + { + return false; + } + + Variables other = (Variables)object; + + if (this.size != other.size) + { + return false; + } + + for (int index = 0; index < size; index++) + { + Value thisValue = this.values[index]; + Value otherValue = other.values[index]; + + // Occasionally, two values of different types might be + // present in the same variable in a variable frame + // (corresponding to two local variables that share the + // same index), at some point outside of their scopes. + // We'll ignore these. + if (thisValue != null && + otherValue != null && + thisValue.computationalType() == otherValue.computationalType() && + !thisValue.equals(otherValue)) + { + return false; + } + } + + return true; + } + + + public int hashCode() + { + int hashCode = size; + + for (int index = 0; index < size; index++) + { + Value value = values[index]; + if (value != null) + { + hashCode ^= value.hashCode(); + } + } + + return hashCode; + } + + + public String toString() + { + StringBuffer buffer = new StringBuffer(); + + for (int index = 0; index < size; index++) + { + Value value = values[index]; + buffer = buffer.append('[') + .append(value == null ? "empty" : value.toString()) + .append(']'); + } + + return buffer.toString(); + } +} |