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