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