OSDN Git Service

Add several classes from dx tool to the dexgen project
[android-x86/dalvik.git] / dexgen / src / com / android / dexgen / rop / code / RegisterSpec.java
diff --git a/dexgen/src/com/android/dexgen/rop/code/RegisterSpec.java b/dexgen/src/com/android/dexgen/rop/code/RegisterSpec.java
new file mode 100644 (file)
index 0000000..30deeca
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dexgen.rop.code;
+
+import com.android.dexgen.rop.cst.Constant;
+import com.android.dexgen.rop.cst.CstUtf8;
+import com.android.dexgen.rop.type.Type;
+import com.android.dexgen.rop.type.TypeBearer;
+import com.android.dexgen.util.ToHuman;
+
+import java.util.HashMap;
+
+/**
+ * Combination of a register number and a type, used as the sources and
+ * destinations of register-based operations.
+ */
+public final class RegisterSpec
+        implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
+    /** {@code non-null;} string to prefix register numbers with */
+    public static final String PREFIX = "v";
+
+    /** {@code non-null;} intern table for instances */
+    private static final HashMap<Object, RegisterSpec> theInterns =
+        new HashMap<Object, RegisterSpec>(1000);
+
+    /** {@code non-null;} common comparison instance used while interning */
+    private static final ForComparison theInterningItem = new ForComparison();
+
+    /** {@code >= 0;} register number */
+    private final int reg;
+
+    /** {@code non-null;} type loaded or stored */
+    private final TypeBearer type;
+
+    /** {@code null-ok;} local variable info associated with this register, if any */
+    private final LocalItem local;
+
+    /**
+     * Intern the given triple as an instance of this class.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated local variable, if any
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    private static RegisterSpec intern(int reg, TypeBearer type,
+            LocalItem local) {
+        theInterningItem.set(reg, type, local);
+        RegisterSpec found = theInterns.get(theInterningItem);
+
+        if (found != null) {
+            return found;
+        }
+
+        found = theInterningItem.toRegisterSpec();
+        theInterns.put(found, found);
+        return found;
+    }
+
+    /**
+     * Returns an instance for the given register number and type, with
+     * no variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec make(int reg, TypeBearer type) {
+        return intern(reg, type, null);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code non-null;} the associated local variable
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec make(int reg, TypeBearer type,
+            LocalItem local) {
+        if (local == null) {
+            throw new NullPointerException("local  == null");
+        }
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Returns an instance for the given register number, type, and
+     * variable info. This method is allowed to return shared
+     * instances (but doesn't necessarily do so).
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated variable info or null for
+     * none
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public static RegisterSpec makeLocalOptional(
+            int reg, TypeBearer type, LocalItem local) {
+
+        return intern(reg, type, local);
+    }
+
+    /**
+     * Gets the string form for the given register number.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @return {@code non-null;} the string form
+     */
+    public static String regString(int reg) {
+        return PREFIX + reg;
+    }
+
+    /**
+     * Constructs an instance. This constructor is private. Use
+     * {@link #make}.
+     *
+     * @param reg {@code >= 0;} the register number
+     * @param type {@code non-null;} the type (or possibly actual value) which
+     * is loaded from or stored to the indicated register
+     * @param local {@code null-ok;} the associated local variable, if any
+     */
+    private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
+        if (reg < 0) {
+            throw new IllegalArgumentException("reg < 0");
+        }
+
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        this.reg = reg;
+        this.type = type;
+        this.local = local;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof RegisterSpec)) {
+            if (other instanceof ForComparison) {
+                ForComparison fc = (ForComparison) other;
+                return equals(fc.reg, fc.type, fc.local);
+            }
+            return false;
+        }
+
+        RegisterSpec spec = (RegisterSpec) other;
+        return equals(spec.reg, spec.type, spec.local);
+    }
+
+    /**
+     * Like {@code equals}, but only consider the simple types of the
+     * registers. That is, this compares {@code getType()} on the types
+     * to ignore whatever arbitrary extra stuff might be carried around
+     * by an outer {@link TypeBearer}.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean equalsUsingSimpleType(RegisterSpec other) {
+        if (!matchesVariable(other)) {
+            return false;
+        }
+
+        return (reg == other.reg);
+    }
+
+    /**
+     * Like {@link #equalsUsingSimpleType} but ignoring the register number.
+     * This is useful to determine if two instances refer to the "same"
+     * local variable.
+     *
+     * @param other {@code null-ok;} spec to compare to
+     * @return {@code true} iff {@code this} and {@code other} are equal
+     * in the stated way
+     */
+    public boolean matchesVariable(RegisterSpec other) {
+        if (other == null) {
+            return false;
+        }
+
+        return type.getType().equals(other.type.getType())
+            && ((local == other.local)
+                    || ((local != null) && local.equals(other.local)));
+    }
+
+    /**
+     * Helper for {@link #equals} and {@link #ForComparison.equals},
+     * which actually does the test.
+     *
+     * @param reg value of the instance variable, for another instance
+     * @param type value of the instance variable, for another instance
+     * @param local value of the instance variable, for another instance
+     * @return whether this instance is equal to one with the given
+     * values
+     */
+    private boolean equals(int reg, TypeBearer type, LocalItem local) {
+        return (this.reg == reg)
+            && this.type.equals(type)
+            && ((this.local == local)
+                    || ((this.local != null) && this.local.equals(local)));
+    }
+
+    /**
+     * Compares by (in priority order) register number, unwrapped type
+     * (that is types not {@link TypeBearer}s, and local info.
+     *
+     * @param other {@code non-null;} spec to compare to
+     * @return {@code -1..1;} standard result of comparison
+     */
+    public int compareTo(RegisterSpec other) {
+        if (this.reg < other.reg) {
+            return -1;
+        } else if (this.reg > other.reg) {
+            return 1;
+        }
+
+        int compare = type.getType().compareTo(other.type.getType());
+
+        if (compare != 0) {
+            return compare;
+        }
+
+        if (this.local == null) {
+            return (other.local == null) ? 0 : -1;
+        } else if (other.local == null) {
+            return 1;
+        }
+
+        return this.local.compareTo(other.local);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return hashCodeOf(reg, type, local);
+    }
+
+    /**
+     * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
+     * which actually does the calculation.
+     *
+     * @param reg value of the instance variable
+     * @param type value of the instance variable
+     * @param local value of the instance variable
+     * @return the hash code
+     */
+    private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
+        int hash = (local != null) ? local.hashCode() : 0;
+
+        hash = (hash * 31 + type.hashCode()) * 31 + reg;
+        return hash;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return toString0(false);
+    }
+
+    /** {@inheritDoc} */
+    public String toHuman() {
+        return toString0(true);
+    }
+
+    /** {@inheritDoc} */
+    public Type getType() {
+        return type.getType();
+    }
+
+    /** {@inheritDoc} */
+    public TypeBearer getFrameType() {
+        return type.getFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicType() {
+        return type.getBasicType();
+    }
+
+    /** {@inheritDoc} */
+    public final int getBasicFrameType() {
+        return type.getBasicFrameType();
+    }
+
+    /** {@inheritDoc} */
+    public final boolean isConstant() {
+        return false;
+    }
+
+    /**
+     * Gets the register number.
+     *
+     * @return {@code >= 0;} the register number
+     */
+    public int getReg() {
+        return reg;
+    }
+
+    /**
+     * Gets the type (or actual value) which is loaded from or stored
+     * to the register associated with this instance.
+     *
+     * @return {@code non-null;} the type
+     */
+    public TypeBearer getTypeBearer() {
+        return type;
+    }
+
+    /**
+     * Gets the variable info associated with this instance, if any.
+     *
+     * @return {@code null-ok;} the variable info, or {@code null} if this
+     * instance has none
+     */
+    public LocalItem getLocalItem() {
+        return local;
+    }
+
+    /**
+     * Gets the next available register number after the one in this
+     * instance. This is equal to the register number plus the width
+     * (category) of the type used. Among other things, this may also
+     * be used to determine the minimum required register count
+     * implied by this instance.
+     *
+     * @return {@code >= 0;} the required registers size
+     */
+    public int getNextReg() {
+        return reg + getCategory();
+    }
+
+    /**
+     * Gets the category of this instance's type. This is just a convenient
+     * shorthand for {@code getType().getCategory()}.
+     *
+     * @see #isCategory1
+     * @see #isCategory2
+     * @return {@code 1..2;} the category of this instance's type
+     */
+    public int getCategory() {
+        return type.getType().getCategory();
+    }
+
+    /**
+     * Gets whether this instance's type is category 1. This is just a
+     * convenient shorthand for {@code getType().isCategory1()}.
+     *
+     * @see #getCategory
+     * @see #isCategory2
+     * @return whether or not this instance's type is of category 1
+     */
+    public boolean isCategory1() {
+        return type.getType().isCategory1();
+    }
+
+    /**
+     * Gets whether this instance's type is category 2. This is just a
+     * convenient shorthand for {@code getType().isCategory2()}.
+     *
+     * @see #getCategory
+     * @see #isCategory1
+     * @return whether or not this instance's type is of category 2
+     */
+    public boolean isCategory2() {
+        return type.getType().isCategory2();
+    }
+
+    /**
+     * Gets the string form for just the register number of this instance.
+     *
+     * @return {@code non-null;} the register string form
+     */
+    public String regString() {
+        return regString(reg);
+    }
+
+    /**
+     * Returns an instance that is the intersection between this instance
+     * and the given one, if any. The intersection is defined as follows:
+     *
+     * <ul>
+     *   <li>If {@code other} is {@code null}, then the result
+     *     is {@code null}.
+     *   <li>If the register numbers don't match, then the intersection
+     *     is {@code null}. Otherwise, the register number of the
+     *     intersection is the same as the one in the two instances.</li>
+     *   <li>If the types returned by {@code getType()} are not
+     *     {@code equals()}, then the intersection is null.</li>
+     *   <li>If the type bearers returned by {@code getTypeBearer()}
+     *     are {@code equals()}, then the intersection's type bearer
+     *     is the one from this instance. Otherwise, the intersection's
+     *     type bearer is the {@code getType()} of this instance.</li>
+     *   <li>If the locals are {@code equals()}, then the local info
+     *     of the intersection is the local info of this instance. Otherwise,
+     *     the local info of the intersection is {@code null}.</li>
+     * </ul>
+     *
+     * @param other {@code null-ok;} instance to intersect with (or {@code null})
+     * @param localPrimary whether local variables are primary to the
+     * intersection; if {@code true}, then the only non-null
+     * results occur when registers being intersected have equal local
+     * infos (or both have {@code null} local infos)
+     * @return {@code null-ok;} the intersection
+     */
+    public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
+        if (this == other) {
+            // Easy out.
+            return this;
+        }
+
+        if ((other == null) || (reg != other.getReg())) {
+            return null;
+        }
+
+        LocalItem resultLocal =
+            ((local == null) || !local.equals(other.getLocalItem()))
+            ? null : local;
+        boolean sameName = (resultLocal == local);
+
+        if (localPrimary && !sameName) {
+            return null;
+        }
+
+        Type thisType = getType();
+        Type otherType = other.getType();
+
+        // Note: Types are always interned.
+        if (thisType != otherType) {
+            return null;
+        }
+
+        TypeBearer resultTypeBearer =
+            type.equals(other.getTypeBearer()) ? type : thisType;
+
+        if ((resultTypeBearer == type) && sameName) {
+            // It turns out that the intersection is "this" after all.
+            return this;
+        }
+
+        return (resultLocal == null) ? make(reg, resultTypeBearer) :
+            make(reg, resultTypeBearer, resultLocal);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is replaced by the given one.
+     *
+     * @param newReg {@code >= 0;} the new register number
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withReg(int newReg) {
+        if (reg == newReg) {
+            return this;
+        }
+
+        return makeLocalOptional(newReg, type, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type is replaced by the given one.
+     *
+     * @param newType {@code non-null;} the new type
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withType(TypeBearer newType) {
+        return makeLocalOptional(reg, newType, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that the
+     * register number is offset by the given amount.
+     *
+     * @param delta the amount to offset the register number by
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withOffset(int delta) {
+        if (delta == 0) {
+            return this;
+        }
+
+        return withReg(reg + delta);
+    }
+
+    /**
+     * Returns an instance that is identical to this one, except that
+     * the type bearer is replaced by the actual underlying type
+     * (thereby stripping off non-type information) with any
+     * initialization information stripped away as well.
+     *
+     * @return {@code non-null;} an appropriately-constructed instance
+     */
+    public RegisterSpec withSimpleType() {
+        TypeBearer orig = type;
+        Type newType;
+
+        if (orig instanceof Type) {
+            newType = (Type) orig;
+        } else {
+            newType = orig.getType();
+        }
+
+        if (newType.isUninitialized()) {
+            newType = newType.getInitializedType();
+        }
+
+        if (newType == orig) {
+            return this;
+        }
+
+        return makeLocalOptional(reg, newType, local);
+    }
+
+    /**
+     * Returns an instance that is identical to this one except that the
+     * local variable is as specified in the parameter.
+     *
+     * @param local {@code null-ok;} the local item or null for none
+     * @return an appropriate instance
+     */
+    public RegisterSpec withLocalItem(LocalItem local) {
+        if ((this.local== local)
+                    || ((this.local != null) && this.local.equals(local))) {
+
+            return this;
+        }
+
+        return makeLocalOptional(reg, type, local);
+    }
+
+
+    /**
+     * Helper for {@link #toString} and {@link #toHuman}.
+     *
+     * @param human whether to be human-oriented
+     * @return {@code non-null;} the string form
+     */
+    private String toString0(boolean human) {
+        StringBuffer sb = new StringBuffer(40);
+
+        sb.append(regString());
+        sb.append(":");
+
+        if (local != null) {
+            sb.append(local.toString());
+        }
+
+        Type justType = type.getType();
+        sb.append(justType);
+
+        if (justType != type) {
+            sb.append("=");
+            if (human && (type instanceof Constant)) {
+                sb.append(((Constant) type).toHuman());
+            } else {
+                sb.append(type);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Holder of register spec data for the purposes of comparison (so that
+     * {@code RegisterSpec} itself can still keep {@code final}
+     * instance variables.
+     */
+    private static class ForComparison {
+        /** {@code >= 0;} register number */
+        private int reg;
+
+        /** {@code non-null;} type loaded or stored */
+        private TypeBearer type;
+
+        /**
+         * {@code null-ok;} local variable associated with this
+         * register, if any
+         */
+        private LocalItem local;
+
+        /**
+         * Set all the instance variables.
+         *
+         * @param reg {@code >= 0;} the register number
+         * @param type {@code non-null;} the type (or possibly actual
+         * value) which is loaded from or stored to the indicated
+         * register
+         * @param local {@code null-ok;} the associated local variable, if any
+         * @return {@code non-null;} an appropriately-constructed instance
+         */
+        public void set(int reg, TypeBearer type, LocalItem local) {
+            this.reg = reg;
+            this.type = type;
+            this.local = local;
+        }
+
+        /**
+         * Construct a {@code RegisterSpec} of this instance's
+         * contents.
+         *
+         * @return {@code non-null;} an appropriately-constructed instance
+         */
+        public RegisterSpec toRegisterSpec() {
+            return new RegisterSpec(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof RegisterSpec)) {
+                return false;
+            }
+
+            RegisterSpec spec = (RegisterSpec) other;
+            return spec.equals(reg, type, local);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int hashCode() {
+            return hashCodeOf(reg, type, local);
+        }
+    }
+}