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.dex.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpec;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecSet;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.FixedSizeList;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.PrintStream;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.ArrayList;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Arrays;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * List of local variables. Each local variable entry indicates a
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * range of code which it is valid for, a register number, a name,
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * and a type.
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class LocalList extends FixedSizeList {
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} empty instance */
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static final LocalList EMPTY = new LocalList(0);
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** whether to run the self-check code */
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final boolean DEBUG = false;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. All indices initially contain {@code null}.
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param size {@code >= 0;} the size of the list
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public LocalList(int size) {
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        super(size);
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the element at the given index. It is an error to call
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * this with the index for an element which was never set; if you
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * do that, this will throw {@code NullPointerException}.
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param n {@code >= 0, < size();} which index
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} element at that index
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Entry get(int n) {
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (Entry) get0(n);
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Sets the entry at the given index.
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param n {@code >= 0, < size();} which index
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param entry {@code non-null;} the entry to set at {@code n}
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void set(int n, Entry entry) {
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        set0(n, entry);
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Does a human-friendly dump of this instance.
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to dump
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix to attach to each line of output
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void debugPrint(PrintStream out, String prefix) {
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = size();
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < sz; i++) {
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.print(prefix);
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.println(get(i));
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Disposition of a local entry.
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static enum Disposition {
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** local started (introduced) */
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        START,
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** local ended without being replaced */
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        END_SIMPLY,
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** local ended because it was directly replaced */
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        END_REPLACED,
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** local ended because it was moved to a different register */
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        END_MOVED,
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local ended because the previous local clobbered this one
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * (because it is category-2)
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        END_CLOBBERED_BY_PREV,
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local ended because the next local clobbered this one
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * (because this one is a category-2)
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        END_CLOBBERED_BY_NEXT;
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Entry in a local list.
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class Entry implements Comparable<Entry> {
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code >= 0;} address */
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final int address;
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} disposition of the local */
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Disposition disposition;
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} register spec representing the variable */
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final RegisterSpec spec;
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} variable type (derived from {@code spec}) */
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final CstType type;
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Constructs an instance.
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} address
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param disposition {@code non-null;} disposition of the local
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param spec {@code non-null;} register spec representing
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the variable
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Entry(int address, Disposition disposition, RegisterSpec spec) {
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (address < 0) {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("address < 0");
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (disposition == null) {
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new NullPointerException("disposition == null");
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            try {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (spec.getLocalItem() == null) {
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new NullPointerException(
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            "spec.getLocalItem() == null");
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } catch (NullPointerException ex) {
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // Elucidate the exception.
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new NullPointerException("spec == null");
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.address = address;
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.disposition = disposition;
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.spec = spec;
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.type = CstType.intern(spec.getType());
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public String toString() {
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return Integer.toHexString(address) + " " + disposition + " " +
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                spec;
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean equals(Object other) {
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!(other instanceof Entry)) {
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return false;
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return (compareTo((Entry) other) == 0);
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Compares by (in priority order) address, end then start
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * disposition (variants of end are all consistered
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * equivalent), and spec.
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param other {@code non-null;} entry to compare to
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code -1..1;} standard result of comparison
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int compareTo(Entry other) {
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (address < other.address) {
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return -1;
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (address > other.address) {
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return 1;
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean thisIsStart = isStart();
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean otherIsStart = other.isStart();
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (thisIsStart != otherIsStart) {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return thisIsStart ? 1 : -1;
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.compareTo(other.spec);
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the address.
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code >= 0;} the address
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getAddress() {
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return address;
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the disposition.
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} the disposition
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Disposition getDisposition() {
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return disposition;
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets whether this is a local start. This is just shorthand for
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code getDisposition() == Disposition.START}.
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code true} iff this is a start
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean isStart() {
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return disposition == Disposition.START;
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the variable name.
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code null-ok;} the variable name
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CstString getName() {
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.getLocalItem().getName();
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the variable signature.
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code null-ok;} the variable signature
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CstString getSignature() {
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.getLocalItem().getSignature();
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the variable's type.
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} the type
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public CstType getType() {
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return type;
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the number of the register holding the variable.
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code >= 0;} the number of the register holding
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the variable
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int getRegister() {
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.getReg();
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Gets the RegisterSpec of the register holding the variable.
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} RegisterSpec of the holding register.
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public RegisterSpec getRegisterSpec() {
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec;
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Returns whether or not this instance matches the given spec.
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param otherSpec {@code non-null;} the spec in question
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code true} iff this instance matches
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code spec}
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean matches(RegisterSpec otherSpec) {
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return spec.equalsUsingSimpleType(otherSpec);
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Returns whether or not this instance matches the spec in
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the given instance.
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param other {@code non-null;} another entry
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code true} iff this instance's spec matches
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code other}
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean matches(Entry other) {
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return matches(other.spec);
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Returns an instance just like this one but with the disposition
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * set as given.
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param disposition {@code non-null;} the new disposition
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} an appropriately-constructed instance
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Entry withDisposition(Disposition disposition) {
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (disposition == this.disposition) {
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return this;
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new Entry(address, disposition, spec);
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance for the given method, based on the given
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * block order and intermediate local information.
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param insns {@code non-null;} instructions to convert
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the constructed list
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static LocalList make(DalvInsnList insns) {
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = insns.size();
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Go through the insn list, looking for all the local
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * variable pseudoinstructions, splitting out LocalSnapshots
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * into separate per-variable starts, adding explicit ends
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * wherever a variable is replaced or moved, and collecting
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * these and all the other local variable "activity"
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * together into an output list (without the other insns).
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Note: As of this writing, this method won't be handed any
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * insn lists that contain local ends, but I (danfuzz) expect
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * that to change at some point, when we start feeding that
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * info explicitly into the rop layer rather than only trying
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * to infer it. So, given that expectation, this code is
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * written to deal with them.
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MakeState state = new MakeState(sz);
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < sz; i++) {
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvInsn insn = insns.get(i);
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (insn instanceof LocalSnapshot) {
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecSet snapshot =
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ((LocalSnapshot) insn).getLocals();
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                state.snapshot(insn.getAddress(), snapshot);
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (insn instanceof LocalStart) {
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec local = ((LocalStart) insn).getLocal();
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                state.startLocal(insn.getAddress(), local);
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (insn instanceof LocalEnd) {
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec local = ((LocalEnd) insn).getLocal();
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                state.endLocal(insn.getAddress(), local);
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        LocalList result = state.finish();
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (DEBUG) {
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            debugVerify(result);
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Debugging helper that verifies the constraint that a list doesn't
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * contain any redundant local starts and that local ends that are
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * due to replacements are properly annotated.
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void debugVerify(LocalList locals) {
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            debugVerify0(locals);
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException ex) {
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int sz = locals.size();
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < sz; i++) {
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.println(locals.get(i));
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw ex;
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #debugVerify} which does most of the work.
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static void debugVerify0(LocalList locals) {
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = locals.size();
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Entry[] active = new Entry[65536];
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < sz; i++) {
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Entry e = locals.get(i);
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int reg = e.getRegister();
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (e.isStart()) {
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Entry already = active[reg];
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if ((already != null) && e.matches(already)) {
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new RuntimeException("redundant start at " +
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            Integer.toHexString(e.getAddress()) + ": got " +
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            e + "; had " + already);
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                active[reg] = e;
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (active[reg] == null) {
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new RuntimeException("redundant end at " +
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            Integer.toHexString(e.getAddress()));
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int addr = e.getAddress();
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                boolean foundStart = false;
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                for (int j = i + 1; j < sz; j++) {
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    Entry test = locals.get(j);
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (test.getAddress() != addr) {
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        break;
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (test.getRegisterSpec().getReg() == reg) {
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        if (test.isStart()) {
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            if (e.getDisposition()
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    != Disposition.END_REPLACED) {
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                throw new RuntimeException(
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                        "improperly marked end at " +
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                        Integer.toHexString(addr));
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            }
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            foundStart = true;
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        } else {
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            throw new RuntimeException(
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    "redundant end at " +
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                    Integer.toHexString(addr));
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        }
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (!foundStart &&
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        (e.getDisposition() == Disposition.END_REPLACED)) {
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new RuntimeException(
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            "improper end replacement claim at " +
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            Integer.toHexString(addr));
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                active[reg] = null;
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Intermediate state when constructing a local list.
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class MakeState {
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} result being collected */
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final ArrayList<Entry> result;
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code >= 0;} running count of nulled result entries, to help with
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * sizing the final list
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int nullResultCount;
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code null-ok;} current register mappings */
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private RegisterSpecSet regs;
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code null-ok;} result indices where local ends are stored */
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int[] endIndices;
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code >= 0;} last address seen */
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int lastAddress;
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Constructs an instance.
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public MakeState(int initialSize) {
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = new ArrayList<Entry>(initialSize);
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            nullResultCount = 0;
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            regs = null;
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            endIndices = null;
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            lastAddress = 0;
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Checks the address and other vitals as a prerequisite to
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * further processing.
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} address about to be processed
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param reg {@code >= 0;} register number about to be processed
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private void aboutToProcess(int address, int reg) {
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean first = (endIndices == null);
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((address == lastAddress) && !first) {
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (address < lastAddress) {
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (first || (reg >= endIndices.length)) {
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * This is the first allocation of the state set and
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * index array, or we need to grow. (The latter doesn't
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * happen much; in fact, we have only ever observed
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * it happening in test cases, never in "real" code.)
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int newSz = reg + 1;
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int[] newEnds = new int[newSz];
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Arrays.fill(newEnds, -1);
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (!first) {
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    newRegs.putAll(regs);
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    System.arraycopy(endIndices, 0, newEnds, 0,
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            endIndices.length);
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                regs = newRegs;
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                endIndices = newEnds;
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Sets the local state at the given address to the given snapshot.
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * The first call on this instance must be to this method, so that
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the register state can be properly sized.
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param specs {@code non-null;} spec set representing the locals
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void snapshot(int address, RegisterSpecSet specs) {
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (DEBUG) {
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.printf("%04x snapshot %s\n", address, specs);
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int sz = specs.getMaxSize();
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            aboutToProcess(address, sz - 1);
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < sz; i++) {
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec oldSpec = regs.get(i);
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec newSpec = filterSpec(specs.get(i));
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (oldSpec == null) {
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (newSpec != null) {
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        startLocal(address, newSpec);
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else if (newSpec == null) {
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    endLocal(address, oldSpec);
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else if (! newSpec.equalsUsingSimpleType(oldSpec)) {
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    endLocal(address, oldSpec);
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    startLocal(address, newSpec);
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (DEBUG) {
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.printf("%04x snapshot done\n", address);
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Starts a local at the given address.
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param startedLocal {@code non-null;} spec representing the
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * started local
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void startLocal(int address, RegisterSpec startedLocal) {
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (DEBUG) {
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.printf("%04x start %s\n", address, startedLocal);
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int regNum = startedLocal.getReg();
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            startedLocal = filterSpec(startedLocal);
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            aboutToProcess(address, regNum);
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec existingLocal = regs.get(regNum);
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (startedLocal.equalsUsingSimpleType(existingLocal)) {
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // Silently ignore a redundant start.
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (movedLocal != null) {
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * The same variable was moved from one register to another.
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * So add an end for its old location.
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int endAt = endIndices[regNum];
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (existingLocal != null) {
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * There is an existing (but non-matching) local.
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Add an explicit end for it.
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                add(address, Disposition.END_REPLACED, existingLocal);
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else if (endAt >= 0) {
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Look for an end local for the same register at the
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * same address. If found, then update it or delete
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * it, depending on whether or not it represents the
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * same variable as the one being started.
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Entry endEntry = result.get(endAt);
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (endEntry.getAddress() == address) {
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (endEntry.matches(startedLocal)) {
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        /*
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * There was already an end local for the same
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * variable at the same address. This turns
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * out to be superfluous, as we are starting
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * up the exact same local. This situation can
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * happen when a single local variable got
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * somehow "split up" during intermediate
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * processing. In any case, rather than represent
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * the end-then-start, just remove the old end.
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         */
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        result.set(endAt, null);
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        nullResultCount++;
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        regs.put(startedLocal);
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        endIndices[regNum] = -1;
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        return;
631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    } else {
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        /*
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * There was a different variable ended at the
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * same address. Update it to indicate that
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * it was ended due to a replacement (rather than
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * ending for no particular reason).
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         */
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        endEntry = endEntry.withDisposition(
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                Disposition.END_REPLACED);
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        result.set(endAt, endEntry);
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * The code above didn't find and remove an unnecessary
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * local end, so we now have to add one or more entries to
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * the output to capture the transition.
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * If the local just below (in the register set at reg-1)
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * is of category-2, then it is ended by this new start.
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (regNum > 0) {
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec justBelow = regs.get(regNum - 1);
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if ((justBelow != null) && justBelow.isCategory2()) {
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    addOrUpdateEnd(address,
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            Disposition.END_CLOBBERED_BY_NEXT,
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            justBelow);
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
662579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Similarly, if this local is category-2, then the local
666579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * just above (if any) is ended by the start now being
667579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * emitted.
668579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
669579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (startedLocal.isCategory2()) {
670579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec justAbove = regs.get(regNum + 1);
671579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (justAbove != null) {
672579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    addOrUpdateEnd(address,
673579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            Disposition.END_CLOBBERED_BY_PREV,
674579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            justAbove);
675579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
676579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
677579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
678579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
679579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * TODO: Add an end for the same local in a different reg,
680579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * if any (that is, if the local migrates from vX to vY,
681579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * we should note that as a local end in vX).
682579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
683579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
684579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            add(address, Disposition.START, startedLocal);
685579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
686579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
687579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
688579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Ends a local at the given address, using the disposition
689579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code END_SIMPLY}.
690579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
691579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
692579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param endedLocal {@code non-null;} spec representing the
693579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local being ended
694579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
695579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void endLocal(int address, RegisterSpec endedLocal) {
696579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            endLocal(address, endedLocal, Disposition.END_SIMPLY);
697579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
698579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
699579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
700579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Ends a local at the given address.
701579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
702579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
703579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param endedLocal {@code non-null;} spec representing the
704579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local being ended
705579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param disposition reason for the end
706579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
707579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void endLocal(int address, RegisterSpec endedLocal,
708579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Disposition disposition) {
709579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (DEBUG) {
710579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                System.err.printf("%04x end %s\n", address, endedLocal);
711579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
712579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
713579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int regNum = endedLocal.getReg();
714579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
715579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            endedLocal = filterSpec(endedLocal);
716579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            aboutToProcess(address, regNum);
717579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
718579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int endAt = endIndices[regNum];
719579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
720579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (endAt >= 0) {
721579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
722579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * The local in the given register is already ended.
723579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Silently return without adding anything to the result.
724579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
725579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
726579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
727579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
728579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Check for start and end at the same address.
729579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (checkForEmptyRange(address, endedLocal)) {
730579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
731579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
732579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
733579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            add(address, disposition, endedLocal);
734579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
735579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
736579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
737579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Helper for {@link #endLocal}, which handles the cases where
738579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * and end local is issued at the same address as a start local
739579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * for the same register. If this case is found, then this
740579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * method will remove the start (as the local was never actually
741579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * active), update the {@link #endIndices} to be accurate, and
742579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * if needed update the newly-active end to reflect an altered
743579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * disposition.
744579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
745579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
746579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param endedLocal {@code non-null;} spec representing the
747579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local being ended
748579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code true} iff this method found the case in question
749579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * and adjusted things accordingly
750579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
751579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private boolean checkForEmptyRange(int address,
752579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec endedLocal) {
753579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int at = result.size() - 1;
754579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Entry entry;
755579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
756579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Look for a previous entry at the same address.
757579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (/*at*/; at >= 0; at--) {
758579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                entry = result.get(at);
759579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
760579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry == null) {
761579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    continue;
762579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
763579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
764579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry.getAddress() != address) {
765579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    // We didn't find any match at the same address.
766579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    return false;
767579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
768579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
769579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry.matches(endedLocal)) {
770579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
771579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
772579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
773579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
774579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
775579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * In fact, we found that the endedLocal had started at the
776579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * same address, so do all the requisite cleanup.
777579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
778579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
779579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            regs.remove(endedLocal);
780579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.set(at, null);
781579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            nullResultCount++;
782579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
783579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int regNum = endedLocal.getReg();
784579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            boolean found = false;
785579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            entry = null;
786579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
787579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // Now look back further to update where the register ended.
788579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (at--; at >= 0; at--) {
789579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                entry = result.get(at);
790579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
791579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry == null) {
792579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    continue;
793579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
794579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
795579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry.getRegisterSpec().getReg() == regNum) {
796579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    found = true;
797579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
798579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
799579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
800579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
801579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (found) {
802579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // We found an end for the same register.
803579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                endIndices[regNum] = at;
804579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
805579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (entry.getAddress() == address) {
806579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * It's still the same address, so update the
808579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * disposition.
809579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
810579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    result.set(at,
811579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            entry.withDisposition(Disposition.END_SIMPLY));
812579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
813579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
814579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
815579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return true;
816579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
817579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
818579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
819579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Converts a given spec into the form acceptable for use in a
820579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * local list. This, in particular, transforms the "known
821579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * null" type into simply {@code Object}. This method needs to
822579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * be called for any spec that is on its way into a locals
823579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * list.
824579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
825579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * <p>This isn't necessarily the cleanest way to achieve the
826579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * goal of not representing known nulls in a locals list, but
827579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * it gets the job done.</p>
828579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
829579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param orig {@code null-ok;} the original spec
830579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code null-ok;} an appropriately modified spec, or the
831579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * original if nothing needs to be done
832579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
833579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private static RegisterSpec filterSpec(RegisterSpec orig) {
834579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
835579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return orig.withType(Type.OBJECT);
836579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
837579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
838579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return orig;
839579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
840579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
841579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
842579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Adds an entry to the result, updating the adjunct tables
843579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * accordingly.
844579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
845579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
846579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param disposition {@code non-null;} the disposition
847579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param spec {@code non-null;} spec representing the local
848579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
849579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private void add(int address, Disposition disposition,
850579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec spec) {
851579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int regNum = spec.getReg();
852579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
853579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.add(new Entry(address, disposition, spec));
854579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
855579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (disposition == Disposition.START) {
856579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                regs.put(spec);
857579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                endIndices[regNum] = -1;
858579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
859579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                regs.remove(spec);
860579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                endIndices[regNum] = result.size() - 1;
861579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
862579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
863579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
864579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
865579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Adds or updates an end local (changing its disposition). If
866579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * this would cause an empty range for a local, this instead
867579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * removes the local entirely.
868579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
869579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param address {@code >= 0;} the address
870579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param disposition {@code non-null;} the disposition
871579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param spec {@code non-null;} spec representing the local
872579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
873579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private void addOrUpdateEnd(int address, Disposition disposition,
874579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec spec) {
875579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (disposition == Disposition.START) {
876579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
877579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
878579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
879579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int regNum = spec.getReg();
880579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int endAt = endIndices[regNum];
881579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
882579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (endAt >= 0) {
883579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // There is a previous end.
884579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Entry endEntry = result.get(endAt);
885579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if ((endEntry.getAddress() == address) &&
886579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        endEntry.getRegisterSpec().equals(spec)) {
887579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
888579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * The end is for the right address and variable, so
889579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * update it.
890579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
891579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    result.set(endAt, endEntry.withDisposition(disposition));
892579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    regs.remove(spec); // TODO: Is this line superfluous?
893579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    return;
894579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
895579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
896579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
897579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            endLocal(address, spec, disposition);
898579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
899579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
900579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Finishes processing altogether and gets the result.
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code non-null;} the result list
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
905579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public LocalList finish() {
906579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            aboutToProcess(Integer.MAX_VALUE, 0);
907579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
908579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int resultSz = result.size();
909579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int finalSz = resultSz - nullResultCount;
910579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
911579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (finalSz == 0) {
912579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return EMPTY;
913579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
914579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
915579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
916579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Collect an array of only the non-null entries, and then
917579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * sort it to get a consistent order for everything: Local
918579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * ends and starts for a given address could come in any
919579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * order, but we want ends before starts as well as
920579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * registers in order (within ends or starts).
921579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
922579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
923579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Entry[] resultArr = new Entry[finalSz];
924579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
925579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (resultSz == finalSz) {
926579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                result.toArray(resultArr);
927579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
928579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int at = 0;
929579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                for (Entry e : result) {
930579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (e != null) {
931579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        resultArr[at++] = e;
932579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
933579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
934579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
935579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
936579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Arrays.sort(resultArr);
937579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
938579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalList resultList = new LocalList(finalSz);
939579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
940579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < finalSz; i++) {
941579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                resultList.set(i, resultArr[i]);
942579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
943579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
944579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            resultList.setImmutable();
945579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return resultList;
946579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
947579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
948579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
949