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;
24
25import 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 */
31public 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     */
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     */
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     */
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     */
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     */
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     */
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
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     */
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     */
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     */
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     */
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
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     */
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
287    public String toString() {
288        return toString0(false);
289    }
290
291    /** {@inheritDoc} */
292    public String toHuman() {
293        return toString0(true);
294    }
295
296    /** {@inheritDoc} */
297    public Type getType() {
298        return type.getType();
299    }
300
301    /** {@inheritDoc} */
302    public TypeBearer getFrameType() {
303        return type.getFrameType();
304    }
305
306    /** {@inheritDoc} */
307    public final int getBasicType() {
308        return type.getBasicType();
309    }
310
311    /** {@inheritDoc} */
312    public final int getBasicFrameType() {
313        return type.getBasicFrameType();
314    }
315
316    /** {@inheritDoc} */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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         */
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         */
636        public RegisterSpec toRegisterSpec() {
637            return new RegisterSpec(reg, type, local);
638        }
639
640        /** {@inheritDoc} */
641        @Override
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
653        public int hashCode() {
654            return hashCodeOf(reg, type, local);
655        }
656    }
657}
658