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