1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.rop.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.Constant;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.TypeBearer;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ToHuman;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.HashMap;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Combination of a register number and a type, used as the sources and
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * destinations of register-based operations.
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class RegisterSpec
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} string to prefix register numbers with */
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static final String PREFIX = "v";
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} intern table for instances */
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final HashMap<Object, RegisterSpec> theInterns =
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        new HashMap<Object, RegisterSpec>(1000);
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} common comparison instance used while interning */
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final ForComparison theInterningItem = new ForComparison();
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code >= 0;} register number */
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int reg;
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} type loaded or stored */
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final TypeBearer type;
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code null-ok;} local variable info associated with this register,
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * if any
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final LocalItem local;
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Intern the given triple as an instance of this class.
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} the type (or possibly actual value) which
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is loaded from or stored to the indicated register
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local {@code null-ok;} the associated local variable, if any
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static RegisterSpec intern(int reg, TypeBearer type,
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalItem local) {
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        synchronized (theInterns) {
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            theInterningItem.set(reg, type, local);
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec found = theInterns.get(theInterningItem);
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (found != null) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return found;
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            found = theInterningItem.toRegisterSpec();
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            theInterns.put(found, found);
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return found;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance for the given register number and type, with
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * no variable info. This method is allowed to return shared
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instances (but doesn't necessarily do so).
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} the type (or possibly actual value) which
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is loaded from or stored to the indicated register
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static RegisterSpec make(int reg, TypeBearer type) {
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return intern(reg, type, null);
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance for the given register number, type, and
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * variable info. This method is allowed to return shared
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instances (but doesn't necessarily do so).
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} the type (or possibly actual value) which
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is loaded from or stored to the indicated register
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local {@code non-null;} the associated local variable
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static RegisterSpec make(int reg, TypeBearer type,
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalItem local) {
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (local == null) {
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("local  == null");
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return intern(reg, type, local);
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance for the given register number, type, and
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * variable info. This method is allowed to return shared
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instances (but doesn't necessarily do so).
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} the type (or possibly actual value) which
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is loaded from or stored to the indicated register
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local {@code null-ok;} the associated variable info or null for
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * none
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static RegisterSpec makeLocalOptional(
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int reg, TypeBearer type, LocalItem local) {
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return intern(reg, type, local);
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the string form for the given register number.
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the string form
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static String regString(int reg) {
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return PREFIX + reg;
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. This constructor is private. Use
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@link #make}.
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg {@code >= 0;} the register number
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type {@code non-null;} the type (or possibly actual value) which
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * is loaded from or stored to the indicated register
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local {@code null-ok;} the associated local variable, if any
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (reg < 0) {
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("reg < 0");
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (type == null) {
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("type == null");
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.reg = reg;
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.type = type;
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.local = local;
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean equals(Object other) {
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!(other instanceof RegisterSpec)) {
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (other instanceof ForComparison) {
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                ForComparison fc = (ForComparison) other;
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return equals(fc.reg, fc.type, fc.local);
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpec spec = (RegisterSpec) other;
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return equals(spec.reg, spec.type, spec.local);
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Like {@code equals}, but only consider the simple types of the
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * registers. That is, this compares {@code getType()} on the types
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to ignore whatever arbitrary extra stuff might be carried around
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * by an outer {@link TypeBearer}.
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param other {@code null-ok;} spec to compare to
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code true} iff {@code this} and {@code other} are equal
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in the stated way
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean equalsUsingSimpleType(RegisterSpec other) {
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!matchesVariable(other)) {
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (reg == other.reg);
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Like {@link #equalsUsingSimpleType} but ignoring the register number.
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This is useful to determine if two instances refer to the "same"
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * local variable.
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param other {@code null-ok;} spec to compare to
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code true} iff {@code this} and {@code other} are equal
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * in the stated way
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean matchesVariable(RegisterSpec other) {
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (other == null) {
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return false;
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getType().equals(other.type.getType())
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            && ((local == other.local)
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    || ((local != null) && local.equals(other.local)));
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #equals} and {@link #ForComparison.equals},
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * which actually does the test.
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg value of the instance variable, for another instance
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type value of the instance variable, for another instance
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local value of the instance variable, for another instance
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return whether this instance is equal to one with the given
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * values
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private boolean equals(int reg, TypeBearer type, LocalItem local) {
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (this.reg == reg)
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            && this.type.equals(type)
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            && ((this.local == local)
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    || ((this.local != null) && this.local.equals(local)));
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Compares by (in priority order) register number, unwrapped type
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (that is types not {@link TypeBearer}s, and local info.
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param other {@code non-null;} spec to compare to
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code -1..1;} standard result of comparison
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int compareTo(RegisterSpec other) {
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (this.reg < other.reg) {
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return -1;
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (this.reg > other.reg) {
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 1;
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int compare = type.getType().compareTo(other.type.getType());
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (compare != 0) {
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return compare;
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (this.local == null) {
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return (other.local == null) ? 0 : -1;
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (other.local == null) {
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return 1;
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return this.local.compareTo(other.local);
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int hashCode() {
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return hashCodeOf(reg, type, local);
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #hashCode} and {@link #ForComparison.hashCode},
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * which actually does the calculation.
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param reg value of the instance variable
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param type value of the instance variable
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local value of the instance variable
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return the hash code
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static int hashCodeOf(int reg, TypeBearer type, LocalItem local) {
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int hash = (local != null) ? local.hashCode() : 0;
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        hash = (hash * 31 + type.hashCode()) * 31 + reg;
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return hash;
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toString() {
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return toString0(false);
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toHuman() {
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return toString0(true);
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Type getType() {
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getType();
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public TypeBearer getFrameType() {
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getFrameType();
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int getBasicType() {
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getBasicType();
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final int getBasicFrameType() {
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getBasicFrameType();
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public final boolean isConstant() {
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return false;
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the register number.
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the register number
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int getReg() {
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return reg;
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the type (or actual value) which is loaded from or stored
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to the register associated with this instance.
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the type
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public TypeBearer getTypeBearer() {
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type;
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the variable info associated with this instance, if any.
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the variable info, or {@code null} if this
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance has none
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public LocalItem getLocalItem() {
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return local;
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the next available register number after the one in this
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance. This is equal to the register number plus the width
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (category) of the type used. Among other things, this may also
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * be used to determine the minimum required register count
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * implied by this instance.
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code >= 0;} the required registers size
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int getNextReg() {
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return reg + getCategory();
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the category of this instance's type. This is just a convenient
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * shorthand for {@code getType().getCategory()}.
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #isCategory1
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #isCategory2
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code 1..2;} the category of this instance's type
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int getCategory() {
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getType().getCategory();
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets whether this instance's type is category 1. This is just a
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * convenient shorthand for {@code getType().isCategory1()}.
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #getCategory
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #isCategory2
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return whether or not this instance's type is of category 1
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean isCategory1() {
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getType().isCategory1();
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets whether this instance's type is category 2. This is just a
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * convenient shorthand for {@code getType().isCategory2()}.
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #getCategory
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @see #isCategory1
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return whether or not this instance's type is of category 2
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public boolean isCategory2() {
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return type.getType().isCategory2();
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the string form for just the register number of this instance.
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the register string form
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String regString() {
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return regString(reg);
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is the intersection between this instance
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * and the given one, if any. The intersection is defined as follows:
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <ul>
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   <li>If {@code other} is {@code null}, then the result
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     is {@code null}.
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   <li>If the register numbers don't match, then the intersection
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     is {@code null}. Otherwise, the register number of the
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     intersection is the same as the one in the two instances.</li>
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   <li>If the types returned by {@code getType()} are not
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     {@code equals()}, then the intersection is null.</li>
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   <li>If the type bearers returned by {@code getTypeBearer()}
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     are {@code equals()}, then the intersection's type bearer
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     is the one from this instance. Otherwise, the intersection's
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     type bearer is the {@code getType()} of this instance.</li>
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   <li>If the locals are {@code equals()}, then the local info
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     of the intersection is the local info of this instance. Otherwise,
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     the local info of the intersection is {@code null}.</li>
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * </ul>
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param other {@code null-ok;} instance to intersect with (or {@code null})
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param localPrimary whether local variables are primary to the
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * intersection; if {@code true}, then the only non-null
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * results occur when registers being intersected have equal local
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * infos (or both have {@code null} local infos)
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code null-ok;} the intersection
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (this == other) {
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Easy out.
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((other == null) || (reg != other.getReg())) {
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        LocalItem resultLocal =
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ((local == null) || !local.equals(other.getLocalItem()))
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ? null : local;
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean sameName = (resultLocal == local);
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (localPrimary && !sameName) {
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type thisType = getType();
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type otherType = other.getType();
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Note: Types are always interned.
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (thisType != otherType) {
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return null;
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeBearer resultTypeBearer =
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            type.equals(other.getTypeBearer()) ? type : thisType;
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((resultTypeBearer == type) && sameName) {
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // It turns out that the intersection is "this" after all.
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (resultLocal == null) ? make(reg, resultTypeBearer) :
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            make(reg, resultTypeBearer, resultLocal);
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is identical to this one, except that the
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register number is replaced by the given one.
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param newReg {@code >= 0;} the new register number
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec withReg(int newReg) {
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (reg == newReg) {
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return makeLocalOptional(newReg, type, local);
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is identical to this one, except that
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the type is replaced by the given one.
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param newType {@code non-null;} the new type
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec withType(TypeBearer newType) {
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return makeLocalOptional(reg, newType, local);
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is identical to this one, except that the
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * register number is offset by the given amount.
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param delta the amount to offset the register number by
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec withOffset(int delta) {
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (delta == 0) {
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return withReg(reg + delta);
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is identical to this one, except that
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * the type bearer is replaced by the actual underlying type
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * (thereby stripping off non-type information) with any
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * initialization information stripped away as well.
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} an appropriately-constructed instance
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec withSimpleType() {
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeBearer orig = type;
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type newType;
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (orig instanceof Type) {
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            newType = (Type) orig;
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            newType = orig.getType();
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (newType.isUninitialized()) {
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            newType = newType.getInitializedType();
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (newType == orig) {
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return makeLocalOptional(reg, newType, local);
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns an instance that is identical to this one except that the
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * local variable is as specified in the parameter.
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param local {@code null-ok;} the local item or null for none
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return an appropriate instance
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public RegisterSpec withLocalItem(LocalItem local) {
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((this.local== local)
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    || ((this.local != null) && this.local.equals(local))) {
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return this;
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return makeLocalOptional(reg, type, local);
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #toString} and {@link #toHuman}.
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param human whether to be human-oriented
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the string form
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private String toString0(boolean human) {
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StringBuffer sb = new StringBuffer(40);
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(regString());
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(":");
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (local != null) {
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append(local.toString());
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Type justType = type.getType();
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        sb.append(justType);
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (justType != type) {
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            sb.append("=");
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (human && (type instanceof CstString)) {
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(((CstString) type).toQuoted());
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (human && (type instanceof Constant)) {
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(type.toHuman());
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                sb.append(type);
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return sb.toString();
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Holder of register spec data for the purposes of comparison (so that
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code RegisterSpec} itself can still keep {@code final}
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instance variables.
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class ForComparison {
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code >= 0;} register number */
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int reg;
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} type loaded or stored */
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private TypeBearer type;
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code null-ok;} local variable associated with this
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * register, if any
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private LocalItem local;
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Set all the instance variables.
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param reg {@code >= 0;} the register number
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param type {@code non-null;} the type (or possibly actual
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * value) which is loaded from or stored to the indicated
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * register
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param local {@code null-ok;} the associated local variable, if any
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} an appropriately-constructed instance
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void set(int reg, TypeBearer type, LocalItem local) {
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.reg = reg;
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.type = type;
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.local = local;
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Construct a {@code RegisterSpec} of this instance's
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * contents.
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} an appropriately-constructed instance
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public RegisterSpec toRegisterSpec() {
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new RegisterSpec(reg, type, local);
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean equals(Object other) {
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!(other instanceof RegisterSpec)) {
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return false;
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec spec = (RegisterSpec) other;
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.equals(reg, type, local);
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int hashCode() {
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return hashCodeOf(reg, type, local);
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
658