summaryrefslogtreecommitdiffstats
path: root/src/proguard/evaluation/TracedVariables.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/evaluation/TracedVariables.java')
-rw-r--r--src/proguard/evaluation/TracedVariables.java229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/proguard/evaluation/TracedVariables.java b/src/proguard/evaluation/TracedVariables.java
new file mode 100644
index 0000000..1ae6ba6
--- /dev/null
+++ b/src/proguard/evaluation/TracedVariables.java
@@ -0,0 +1,229 @@
+/*
+ * ProGuard -- shrinking, optimization, obfuscation, and preverification
+ * of Java bytecode.
+ *
+ * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
+ *
+ * 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.Value;
+
+/**
+ * This Variables class saves additional information with variables, to keep
+ * track of their origins.
+ * <p>
+ * The Variables class stores a given producer Value along with each Value it
+ * stores. It then generalizes a given collected Value with the producer Value
+ * of each Value it loads. The producer Value and the initial collected Value
+ * can be set; the generalized collected Value can be retrieved.
+ * <p>
+ * In addition, an initialization index can be reset and retrieved, pointing
+ * to the most recent variable that has been initialized by a store operation.
+ *
+ * @author Eric Lafortune
+ */
+public class TracedVariables extends Variables
+{
+ public static final int NONE = -1;
+
+
+ private Value producerValue;
+ private Variables producerVariables;
+ private int initializationIndex;
+
+
+ /**
+ * Creates a new TracedVariables with a given size.
+ */
+ public TracedVariables(int size)
+ {
+ super(size);
+
+ producerVariables = new Variables(size);
+ }
+
+
+ /**
+ * Creates a new TracedVariables that is a copy of the given TracedVariables.
+ */
+ public TracedVariables(TracedVariables tracedVariables)
+ {
+ super(tracedVariables);
+
+ producerVariables = new Variables(tracedVariables.producerVariables);
+ }
+
+
+ /**
+ * Sets the Value that will be stored along with all store instructions.
+ */
+ public void setProducerValue(Value producerValue)
+ {
+ this.producerValue = producerValue;
+ }
+
+
+ /**
+ * Resets the initialization index.
+ */
+ public void resetInitialization()
+ {
+ initializationIndex = NONE;
+ }
+
+
+ /**
+ * Returns the most recent initialization index since it has been reset.
+ */
+ public int getInitializationIndex()
+ {
+ return initializationIndex;
+ }
+
+
+ /**
+ * Gets the producer Value for the specified variable, without disturbing it.
+ * @param index the variable index.
+ * @return the producer value of the given variable.
+ */
+ public Value getProducerValue(int index)
+ {
+ return producerVariables.getValue(index);
+ }
+
+
+ /**
+ * Sets the given producer Value for the specified variable, without
+ * disturbing it.
+ * @param index the variable index.
+ * @param value the producer value to set.
+ */
+ public void setProducerValue(int index, Value value)
+ {
+ producerVariables.store(index, value);
+ }
+
+
+ // Implementations for Variables.
+
+ public void reset(int size)
+ {
+ super.reset(size);
+
+ producerVariables.reset(size);
+ }
+
+ public void initialize(TracedVariables other)
+ {
+ super.initialize(other);
+
+ producerVariables.initialize(other.producerVariables);
+ }
+
+ public boolean generalize(TracedVariables other,
+ boolean clearConflictingOtherVariables)
+ {
+ boolean variablesChanged = super.generalize(other, clearConflictingOtherVariables);
+ boolean producersChanged = producerVariables.generalize(other.producerVariables, clearConflictingOtherVariables);
+ /* consumerVariables.generalize(other.consumerVariables)*/
+
+ // Clear any traces if a variable has become null.
+ if (variablesChanged)
+ {
+ for (int index = 0; index < size; index++)
+ {
+ if (values[index] == null)
+ {
+ producerVariables.values[index] = null;
+
+ if (clearConflictingOtherVariables)
+ {
+ other.producerVariables.values[index] = null;
+ }
+ }
+ }
+ }
+
+ return variablesChanged || producersChanged;
+ }
+
+
+ public void store(int index, Value value)
+ {
+ // Is this store operation an initialization of the variable?
+ Value previousValue = super.load(index);
+ if (previousValue == null ||
+ previousValue.computationalType() != value.computationalType())
+ {
+ initializationIndex = index;
+ }
+
+ // Store the value itself in the variable.
+ super.store(index, value);
+
+ // Store the producer value in its producer variable.
+ producerVariables.store(index, producerValue);
+
+ // Account for the extra space required by Category 2 values.
+ if (value.isCategory2())
+ {
+ producerVariables.store(index+1, producerValue);
+ }
+ }
+
+
+ // Implementations for Object.
+
+ public boolean equals(Object object)
+ {
+ if (object == null ||
+ this.getClass() != object.getClass())
+ {
+ return false;
+ }
+
+ TracedVariables other = (TracedVariables)object;
+
+ return super.equals(object) &&
+ this.producerVariables.equals(other.producerVariables);
+ }
+
+
+ public int hashCode()
+ {
+ return super.hashCode() ^
+ producerVariables.hashCode();
+ }
+
+
+ public String toString()
+ {
+ StringBuffer buffer = new StringBuffer();
+
+ for (int index = 0; index < this.size(); index++)
+ {
+ Value value = this.values[index];
+ Value producerValue = producerVariables.getValue(index);
+ buffer = buffer.append('[')
+ .append(producerValue == null ? "empty:" : producerValue.toString())
+ .append(value == null ? "empty" : value.toString())
+ .append(']');
+ }
+
+ return buffer.toString();
+ }
+}