Home | History | Annotate | Download | only in code
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dexgen.rop.code;
     18 
     19 import com.android.dexgen.rop.cst.Constant;
     20 import com.android.dexgen.rop.cst.CstUtf8;
     21 import com.android.dexgen.rop.type.Type;
     22 import com.android.dexgen.rop.type.TypeBearer;
     23 import com.android.dexgen.util.ToHuman;
     24 
     25 import java.util.HashMap;
     26 
     27 /**
     28  * Combination of a register number and a type, used as the sources and
     29  * destinations of register-based operations.
     30  */
     31 public final class RegisterSpec
     32         implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
     33     /** {@code non-null;} string to prefix register numbers with */
     34     public static final String PREFIX = "v";
     35 
     36     /** {@code non-null;} intern table for instances */
     37     private static final HashMap<Object, RegisterSpec> theInterns =
     38         new HashMap<Object, RegisterSpec>(1000);
     39 
     40     /** {@code non-null;} common comparison instance used while interning */
     41     private static final ForComparison theInterningItem = new ForComparison();
     42 
     43     /** {@code >= 0;} register number */
     44     private final int reg;
     45 
     46     /** {@code non-null;} type loaded or stored */
     47     private final TypeBearer type;
     48 
     49     /** {@code null-ok;} local variable info associated with this register, if any */
     50     private final LocalItem local;
     51 
     52     /**
     53      * Intern the given triple as an instance of this class.
     54      *
     55      * @param reg {@code >= 0;} the register number
     56      * @param type {@code non-null;} the type (or possibly actual value) which
     57      * is loaded from or stored to the indicated register
     58      * @param local {@code null-ok;} the associated local variable, if any
     59      * @return {@code non-null;} an appropriately-constructed instance
     60      */
     61     private static RegisterSpec intern(int reg, TypeBearer type,
     62             LocalItem local) {
     63         theInterningItem.set(reg, type, local);
     64         RegisterSpec found = theInterns.get(theInterningItem);
     65 
     66         if (found != null) {
     67             return found;
     68         }
     69 
     70         found = theInterningItem.toRegisterSpec();
     71         theInterns.put(found, found);
     72         return found;
     73     }
     74 
     75     /**
     76      * Returns an instance for the given register number and type, with
     77      * no variable info. This method is allowed to return shared
     78      * instances (but doesn't necessarily do so).
     79      *
     80      * @param reg {@code >= 0;} the register number
     81      * @param type {@code non-null;} the type (or possibly actual value) which
     82      * is loaded from or stored to the indicated register
     83      * @return {@code non-null;} an appropriately-constructed instance
     84      */
     85     public static RegisterSpec make(int reg, TypeBearer type) {
     86         return intern(reg, type, null);
     87     }
     88 
     89     /**
     90      * Returns an instance for the given register number, type, and
     91      * variable info. This method is allowed to return shared
     92      * instances (but doesn't necessarily do so).
     93      *
     94      * @param reg {@code >= 0;} the register number
     95      * @param type {@code non-null;} the type (or possibly actual value) which
     96      * is loaded from or stored to the indicated register
     97      * @param local {@code non-null;} the associated local variable
     98      * @return {@code non-null;} an appropriately-constructed instance
     99      */
    100     public static RegisterSpec make(int reg, TypeBearer type,
    101             LocalItem local) {
    102         if (local == null) {
    103             throw new NullPointerException("local  == null");
    104         }
    105 
    106         return intern(reg, type, local);
    107     }
    108 
    109     /**
    110      * Returns an instance for the given register number, type, and
    111      * variable info. This method is allowed to return shared
    112      * instances (but doesn't necessarily do so).
    113      *
    114      * @param reg {@code >= 0;} the register number
    115      * @param type {@code non-null;} the type (or possibly actual value) which
    116      * is loaded from or stored to the indicated register
    117      * @param local {@code null-ok;} the associated variable info or null for
    118      * none
    119      * @return {@code non-null;} an appropriately-constructed instance
    120      */
    121     public static RegisterSpec makeLocalOptional(
    122             int reg, TypeBearer type, LocalItem local) {
    123 
    124         return intern(reg, type, local);
    125     }
    126 
    127     /**
    128      * Gets the string form for the given register number.
    129      *
    130      * @param reg {@code >= 0;} the register number
    131      * @return {@code non-null;} the string form
    132      */
    133     public static String regString(int reg) {
    134         return PREFIX + reg;
    135     }
    136 
    137     /**
    138      * Constructs an instance. This constructor is private. Use
    139      * {@link #make}.
    140      *
    141      * @param reg {@code >= 0;} the register number
    142      * @param type {@code non-null;} the type (or possibly actual value) which
    143      * is loaded from or stored to the indicated register
    144      * @param local {@code null-ok;} the associated local variable, if any
    145      */
    146     private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
    147         if (reg < 0) {
    148             throw new IllegalArgumentException("reg < 0");
    149         }
    150 
    151         if (type == null) {
    152             throw new NullPointerException("type == null");
    153         }
    154 
    155         this.reg = reg;
    156         this.type = type;
    157         this.local = local;
    158     }
    159 
    160     /** {@inheritDoc} */
    161     @Override
    162     public boolean equals(Object other) {
    163         if (!(other instanceof RegisterSpec)) {
    164             if (other instanceof ForComparison) {
    165                 ForComparison fc = (ForComparison) other;
    166                 return equals(fc.reg, fc.type, fc.local);
    167             }
    168             return false;
    169         }
    170 
    171         RegisterSpec spec = (RegisterSpec) other;
    172         return equals(spec.reg, spec.type, spec.local);
    173     }
    174 
    175     /**
    176      * Like {@code equals}, but only consider the simple types of the
    177      * registers. That is, this compares {@code getType()} on the types
    178      * to ignore whatever arbitrary extra stuff might be carried around
    179      * by an outer {@link TypeBearer}.
    180      *
    181      * @param other {@code null-ok;} spec to compare to
    182      * @return {@code true} iff {@code this} and {@code other} are equal
    183      * in the stated way
    184      */
    185     public boolean equalsUsingSimpleType(RegisterSpec other) {
    186         if (!matchesVariable(other)) {
    187             return false;
    188         }
    189 
    190         return (reg == other.reg);
    191     }
    192 
    193     /**
    194      * Like {@link #equalsUsingSimpleType} but ignoring the register number.
    195      * This is useful to determine if two instances refer to the "same"
    196      * local variable.
    197      *
    198      * @param other {@code null-ok;} spec to compare to
    199      * @return {@code true} iff {@code this} and {@code other} are equal
    200      * in the stated way
    201      */
    202     public boolean matchesVariable(RegisterSpec other) {
    203         if (other == null) {
    204             return false;
    205         }
    206 
    207         return type.getType().equals(other.type.getType())
    208             && ((local == other.local)
    209                     || ((local != null) && local.equals(other.local)));
    210     }
    211 
    212     /**
    213      * Helper for {@link #equals} and {@link #ForComparison.equals},
    214      * which actually does the test.
    215      *
    216      * @param reg value of the instance variable, for another instance
    217      * @param type value of the instance variable, for another instance
    218      * @param local value of the instance variable, for another instance
    219      * @return whether this instance is equal to one with the given
    220      * values
    221      */
    222     private boolean equals(int reg, TypeBearer type, LocalItem local) {
    223         return (this.reg == reg)
    224             && this.type.equals(type)
    225             && ((this.local == local)
    226                     || ((this.local != null) && this.local.equals(local)));
    227     }
    228 
    229     /**
    230      * Compares by (in priority order) register number, unwrapped type
    231      * (that is types not {@link TypeBearer}s, and local info.
    232      *
    233      * @param other {@code non-null;} spec to compare to
    234      * @return {@code -1..1;} standard result of comparison
    235      */
    236     public int compareTo(RegisterSpec other) {
    237         if (this.reg < other.reg) {
    238             return -1;
    239         } else if (this.reg > other.reg) {
    240             return 1;
    241         }
    242 
    243         int compare = type.getType().compareTo(other.type.getType());
    244 
    245         if (compare != 0) {
    246             return compare;
    247         }
    248 
    249         if (this.local == null) {
    250             return (other.local == null) ? 0 : -1;
    251         } else if (other.local == null) {
    252             return 1;
    253         }
    254 
    255         return this.local.compareTo(other.local);
    256     }
    257 
    258     /** {@inheritDoc} */
    259     @Override
    260     public int hashCode() {
    261         return hashCodeOf(reg, type, local);
    262     }
    263 
    264     /**
    265      * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
    266      * which actually does the calculation.
    267      *
    268      * @param reg value of the instance variable
    269      * @param type value of the instance variable
    270      * @param local value of the instance variable
    271      * @return the hash code
    272      */
    273     private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
    274         int hash = (local != null) ? local.hashCode() : 0;
    275 
    276         hash = (hash * 31 + type.hashCode()) * 31 + reg;
    277         return hash;
    278     }
    279 
    280     /** {@inheritDoc} */
    281     @Override
    282     public String toString() {
    283         return toString0(false);
    284     }
    285 
    286     /** {@inheritDoc} */
    287     public String toHuman() {
    288         return toString0(true);
    289     }
    290 
    291     /** {@inheritDoc} */
    292     public Type getType() {
    293         return type.getType();
    294     }
    295 
    296     /** {@inheritDoc} */
    297     public TypeBearer getFrameType() {
    298         return type.getFrameType();
    299     }
    300 
    301     /** {@inheritDoc} */
    302     public final int getBasicType() {
    303         return type.getBasicType();
    304     }
    305 
    306     /** {@inheritDoc} */
    307     public final int getBasicFrameType() {
    308         return type.getBasicFrameType();
    309     }
    310 
    311     /** {@inheritDoc} */
    312     public final boolean isConstant() {
    313         return false;
    314     }
    315 
    316     /**
    317      * Gets the register number.
    318      *
    319      * @return {@code >= 0;} the register number
    320      */
    321     public int getReg() {
    322         return reg;
    323     }
    324 
    325     /**
    326      * Gets the type (or actual value) which is loaded from or stored
    327      * to the register associated with this instance.
    328      *
    329      * @return {@code non-null;} the type
    330      */
    331     public TypeBearer getTypeBearer() {
    332         return type;
    333     }
    334 
    335     /**
    336      * Gets the variable info associated with this instance, if any.
    337      *
    338      * @return {@code null-ok;} the variable info, or {@code null} if this
    339      * instance has none
    340      */
    341     public LocalItem getLocalItem() {
    342         return local;
    343     }
    344 
    345     /**
    346      * Gets the next available register number after the one in this
    347      * instance. This is equal to the register number plus the width
    348      * (category) of the type used. Among other things, this may also
    349      * be used to determine the minimum required register count
    350      * implied by this instance.
    351      *
    352      * @return {@code >= 0;} the required registers size
    353      */
    354     public int getNextReg() {
    355         return reg + getCategory();
    356     }
    357 
    358     /**
    359      * Gets the category of this instance's type. This is just a convenient
    360      * shorthand for {@code getType().getCategory()}.
    361      *
    362      * @see #isCategory1
    363      * @see #isCategory2
    364      * @return {@code 1..2;} the category of this instance's type
    365      */
    366     public int getCategory() {
    367         return type.getType().getCategory();
    368     }
    369 
    370     /**
    371      * Gets whether this instance's type is category 1. This is just a
    372      * convenient shorthand for {@code getType().isCategory1()}.
    373      *
    374      * @see #getCategory
    375      * @see #isCategory2
    376      * @return whether or not this instance's type is of category 1
    377      */
    378     public boolean isCategory1() {
    379         return type.getType().isCategory1();
    380     }
    381 
    382     /**
    383      * Gets whether this instance's type is category 2. This is just a
    384      * convenient shorthand for {@code getType().isCategory2()}.
    385      *
    386      * @see #getCategory
    387      * @see #isCategory1
    388      * @return whether or not this instance's type is of category 2
    389      */
    390     public boolean isCategory2() {
    391         return type.getType().isCategory2();
    392     }
    393 
    394     /**
    395      * Gets the string form for just the register number of this instance.
    396      *
    397      * @return {@code non-null;} the register string form
    398      */
    399     public String regString() {
    400         return regString(reg);
    401     }
    402 
    403     /**
    404      * Returns an instance that is the intersection between this instance
    405      * and the given one, if any. The intersection is defined as follows:
    406      *
    407      * <ul>
    408      *   <li>If {@code other} is {@code null}, then the result
    409      *     is {@code null}.
    410      *   <li>If the register numbers don't match, then the intersection
    411      *     is {@code null}. Otherwise, the register number of the
    412      *     intersection is the same as the one in the two instances.</li>
    413      *   <li>If the types returned by {@code getType()} are not
    414      *     {@code equals()}, then the intersection is null.</li>
    415      *   <li>If the type bearers returned by {@code getTypeBearer()}
    416      *     are {@code equals()}, then the intersection's type bearer
    417      *     is the one from this instance. Otherwise, the intersection's
    418      *     type bearer is the {@code getType()} of this instance.</li>
    419      *   <li>If the locals are {@code equals()}, then the local info
    420      *     of the intersection is the local info of this instance. Otherwise,
    421      *     the local info of the intersection is {@code null}.</li>
    422      * </ul>
    423      *
    424      * @param other {@code null-ok;} instance to intersect with (or {@code null})
    425      * @param localPrimary whether local variables are primary to the
    426      * intersection; if {@code true}, then the only non-null
    427      * results occur when registers being intersected have equal local
    428      * infos (or both have {@code null} local infos)
    429      * @return {@code null-ok;} the intersection
    430      */
    431     public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
    432         if (this == other) {
    433             // Easy out.
    434             return this;
    435         }
    436 
    437         if ((other == null) || (reg != other.getReg())) {
    438             return null;
    439         }
    440 
    441         LocalItem resultLocal =
    442             ((local == null) || !local.equals(other.getLocalItem()))
    443             ? null : local;
    444         boolean sameName = (resultLocal == local);
    445 
    446         if (localPrimary && !sameName) {
    447             return null;
    448         }
    449 
    450         Type thisType = getType();
    451         Type otherType = other.getType();
    452 
    453         // Note: Types are always interned.
    454         if (thisType != otherType) {
    455             return null;
    456         }
    457 
    458         TypeBearer resultTypeBearer =
    459             type.equals(other.getTypeBearer()) ? type : thisType;
    460 
    461         if ((resultTypeBearer == type) && sameName) {
    462             // It turns out that the intersection is "this" after all.
    463             return this;
    464         }
    465 
    466         return (resultLocal == null) ? make(reg, resultTypeBearer) :
    467             make(reg, resultTypeBearer, resultLocal);
    468     }
    469 
    470     /**
    471      * Returns an instance that is identical to this one, except that the
    472      * register number is replaced by the given one.
    473      *
    474      * @param newReg {@code >= 0;} the new register number
    475      * @return {@code non-null;} an appropriately-constructed instance
    476      */
    477     public RegisterSpec withReg(int newReg) {
    478         if (reg == newReg) {
    479             return this;
    480         }
    481 
    482         return makeLocalOptional(newReg, type, local);
    483     }
    484 
    485     /**
    486      * Returns an instance that is identical to this one, except that
    487      * the type is replaced by the given one.
    488      *
    489      * @param newType {@code non-null;} the new type
    490      * @return {@code non-null;} an appropriately-constructed instance
    491      */
    492     public RegisterSpec withType(TypeBearer newType) {
    493         return makeLocalOptional(reg, newType, local);
    494     }
    495 
    496     /**
    497      * Returns an instance that is identical to this one, except that the
    498      * register number is offset by the given amount.
    499      *
    500      * @param delta the amount to offset the register number by
    501      * @return {@code non-null;} an appropriately-constructed instance
    502      */
    503     public RegisterSpec withOffset(int delta) {
    504         if (delta == 0) {
    505             return this;
    506         }
    507 
    508         return withReg(reg + delta);
    509     }
    510 
    511     /**
    512      * Returns an instance that is identical to this one, except that
    513      * the type bearer is replaced by the actual underlying type
    514      * (thereby stripping off non-type information) with any
    515      * initialization information stripped away as well.
    516      *
    517      * @return {@code non-null;} an appropriately-constructed instance
    518      */
    519     public RegisterSpec withSimpleType() {
    520         TypeBearer orig = type;
    521         Type newType;
    522 
    523         if (orig instanceof Type) {
    524             newType = (Type) orig;
    525         } else {
    526             newType = orig.getType();
    527         }
    528 
    529         if (newType.isUninitialized()) {
    530             newType = newType.getInitializedType();
    531         }
    532 
    533         if (newType == orig) {
    534             return this;
    535         }
    536 
    537         return makeLocalOptional(reg, newType, local);
    538     }
    539 
    540     /**
    541      * Returns an instance that is identical to this one except that the
    542      * local variable is as specified in the parameter.
    543      *
    544      * @param local {@code null-ok;} the local item or null for none
    545      * @return an appropriate instance
    546      */
    547     public RegisterSpec withLocalItem(LocalItem local) {
    548         if ((this.local== local)
    549                     || ((this.local != null) && this.local.equals(local))) {
    550 
    551             return this;
    552         }
    553 
    554         return makeLocalOptional(reg, type, local);
    555     }
    556 
    557 
    558     /**
    559      * Helper for {@link #toString} and {@link #toHuman}.
    560      *
    561      * @param human whether to be human-oriented
    562      * @return {@code non-null;} the string form
    563      */
    564     private String toString0(boolean human) {
    565         StringBuffer sb = new StringBuffer(40);
    566 
    567         sb.append(regString());
    568         sb.append(":");
    569 
    570         if (local != null) {
    571             sb.append(local.toString());
    572         }
    573 
    574         Type justType = type.getType();
    575         sb.append(justType);
    576 
    577         if (justType != type) {
    578             sb.append("=");
    579             if (human && (type instanceof Constant)) {
    580                 sb.append(((Constant) type).toHuman());
    581             } else {
    582                 sb.append(type);
    583             }
    584         }
    585 
    586         return sb.toString();
    587     }
    588 
    589     /**
    590      * Holder of register spec data for the purposes of comparison (so that
    591      * {@code RegisterSpec} itself can still keep {@code final}
    592      * instance variables.
    593      */
    594     private static class ForComparison {
    595         /** {@code >= 0;} register number */
    596         private int reg;
    597 
    598         /** {@code non-null;} type loaded or stored */
    599         private TypeBearer type;
    600 
    601         /**
    602          * {@code null-ok;} local variable associated with this
    603          * register, if any
    604          */
    605         private LocalItem local;
    606 
    607         /**
    608          * Set all the instance variables.
    609          *
    610          * @param reg {@code >= 0;} the register number
    611          * @param type {@code non-null;} the type (or possibly actual
    612          * value) which is loaded from or stored to the indicated
    613          * register
    614          * @param local {@code null-ok;} the associated local variable, if any
    615          * @return {@code non-null;} an appropriately-constructed instance
    616          */
    617         public void set(int reg, TypeBearer type, LocalItem local) {
    618             this.reg = reg;
    619             this.type = type;
    620             this.local = local;
    621         }
    622 
    623         /**
    624          * Construct a {@code RegisterSpec} of this instance's
    625          * contents.
    626          *
    627          * @return {@code non-null;} an appropriately-constructed instance
    628          */
    629         public RegisterSpec toRegisterSpec() {
    630             return new RegisterSpec(reg, type, local);
    631         }
    632 
    633         /** {@inheritDoc} */
    634         @Override
    635         public boolean equals(Object other) {
    636             if (!(other instanceof RegisterSpec)) {
    637                 return false;
    638             }
    639 
    640             RegisterSpec spec = (RegisterSpec) other;
    641             return spec.equals(reg, type, local);
    642         }
    643 
    644         /** {@inheritDoc} */
    645         @Override
    646         public int hashCode() {
    647             return hashCodeOf(reg, type, local);
    648         }
    649     }
    650 }
    651