1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/*
2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project
3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License");
5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License.
6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at
7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *      http://www.apache.org/licenses/LICENSE-2.0
9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul *
10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software
11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS,
12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and
14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License.
15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.code;
18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpec;
20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.code.RegisterSpecSet;
21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstType;
22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.cst.CstUtf8;
23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.rop.type.Type;
24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.FixedSizeList;
25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.io.PrintStream;
27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList;
28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Arrays;
29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/**
31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * List of local variables. Each local variable entry indicates a
32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * range of code which it is valid for, a register number, a name,
33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * and a type.
34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */
35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class LocalList extends FixedSizeList {
36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** {@code non-null;} empty instance */
37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static final LocalList EMPTY = new LocalList(0);
38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /** whether to run the self-check code */
40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static final boolean DEBUG = false;
41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance. All indices initially contain {@code null}.
44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param size {@code >= 0;} the size of the list
46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public LocalList(int size) {
48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        super(size);
49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Gets the element at the given index. It is an error to call
53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * this with the index for an element which was never set; if you
54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * do that, this will throw {@code NullPointerException}.
55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param n {@code >= 0, < size();} which index
57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} element at that index
58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public Entry get(int n) {
60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return (Entry) get0(n);
61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Sets the entry at the given index.
65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param n {@code >= 0, < size();} which index
67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param entry {@code non-null;} the entry to set at {@code n}
68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void set(int n, Entry entry) {
70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        set0(n, entry);
71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Does a human-friendly dump of this instance.
75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param out {@code non-null;} where to dump
77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param prefix {@code non-null;} prefix to attach to each line of output
78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public void debugPrint(PrintStream out, String prefix) {
80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = size();
81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.print(prefix);
84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            out.println(get(i));
85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Disposition of a local entry.
90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static enum Disposition {
92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** local started (introduced) */
93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        START,
94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** local ended without being replaced */
96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        END_SIMPLY,
97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** local ended because it was directly replaced */
99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        END_REPLACED,
100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** local ended because it was moved to a different register */
102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        END_MOVED,
103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local ended because the previous local clobbered this one
106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * (because it is category-2)
107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        END_CLOBBERED_BY_PREV,
109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local ended because the next local clobbered this one
112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * (because this one is a category-2)
113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        END_CLOBBERED_BY_NEXT;
115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Entry in a local list.
119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static class Entry implements Comparable<Entry> {
121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code >= 0;} address */
122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final int address;
123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} disposition of the local */
125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final Disposition disposition;
126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} register spec representing the variable */
128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final RegisterSpec spec;
129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} variable type (derived from {@code spec}) */
131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final CstType type;
132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Constructs an instance.
135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} address
137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param disposition {@code non-null;} disposition of the local
138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param spec {@code non-null;} register spec representing
139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the variable
140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public Entry(int address, Disposition disposition, RegisterSpec spec) {
142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (address < 0) {
143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new IllegalArgumentException("address < 0");
144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (disposition == null) {
147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new NullPointerException("disposition == null");
148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            try {
151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (spec.getLocalItem() == null) {
152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new NullPointerException(
153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            "spec.getLocalItem() == null");
154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } catch (NullPointerException ex) {
156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Elucidate the exception.
157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new NullPointerException("spec == null");
158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.address = address;
161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.disposition = disposition;
162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.spec = spec;
163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            this.type = CstType.intern(spec.getType());
164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public String toString() {
168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return Integer.toHexString(address) + " " + disposition + " " +
169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                spec;
170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@inheritDoc} */
173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean equals(Object other) {
174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (!(other instanceof Entry)) {
175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return false;
176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return (compareTo((Entry) other) == 0);
179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Compares by (in priority order) address, end then start
183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * disposition (variants of end are all consistered
184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * equivalent), and spec.
185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param other {@code non-null;} entry to compare to
187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code -1..1;} standard result of comparison
188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int compareTo(Entry other) {
190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (address < other.address) {
191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return -1;
192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else if (address > other.address) {
193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return 1;
194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean thisIsStart = isStart();
197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean otherIsStart = other.isStart();
198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (thisIsStart != otherIsStart) {
200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return thisIsStart ? 1 : -1;
201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec.compareTo(other.spec);
204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the address.
208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code >= 0;} the address
210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int getAddress() {
212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return address;
213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the disposition.
217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code non-null;} the disposition
219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public Disposition getDisposition() {
221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return disposition;
222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets whether this is a local start. This is just shorthand for
226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code getDisposition() == Disposition.START}.
227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code true} iff this is a start
229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean isStart() {
231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return disposition == Disposition.START;
232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the variable name.
236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code null-ok;} the variable name
238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public CstUtf8 getName() {
240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec.getLocalItem().getName();
241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the variable signature.
245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code null-ok;} the variable signature
247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public CstUtf8 getSignature() {
249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec.getLocalItem().getSignature();
250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the variable's type.
254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code non-null;} the type
256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public CstType getType() {
258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return type;
259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the number of the register holding the variable.
263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code >= 0;} the number of the register holding
265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the variable
266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public int getRegister() {
268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec.getReg();
269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Gets the RegisterSpec of the register holding the variable.
273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code non-null;} RegisterSpec of the holding register.
275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public RegisterSpec getRegisterSpec() {
277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec;
278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Returns whether or not this instance matches the given spec.
282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param otherSpec {@code non-null;} the spec in question
284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code true} iff this instance matches
285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code spec}
286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean matches(RegisterSpec otherSpec) {
288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return spec.equalsUsingSimpleType(otherSpec);
289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Returns whether or not this instance matches the spec in
293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the given instance.
294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param other {@code non-null;} another entry
296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code true} iff this instance's spec matches
297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code other}
298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public boolean matches(Entry other) {
300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return matches(other.spec);
301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Returns an instance just like this one but with the disposition
305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * set as given.
306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param disposition {@code non-null;} the new disposition
308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code non-null;} an appropriately-constructed instance
309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public Entry withDisposition(Disposition disposition) {
311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (disposition == this.disposition) {
312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return this;
313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return new Entry(address, disposition, spec);
316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Constructs an instance for the given method, based on the given
321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * block order and intermediate local information.
322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     *
323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @param insns {@code non-null;} instructions to convert
324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * @return {@code non-null;} the constructed list
325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static LocalList make(DalvInsnList insns) {
327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = insns.size();
328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /*
330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Go through the insn list, looking for all the local
331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * variable pseudoinstructions, splitting out LocalSnapshots
332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * into separate per-variable starts, adding explicit ends
333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * wherever a variable is replaced or moved, and collecting
334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * these and all the other local variable "activity"
335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * together into an output list (without the other insns).
336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Note: As of this writing, this method won't be handed any
338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * insn lists that contain local ends, but I (danfuzz) expect
339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * that to change at some point, when we start feeding that
340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * info explicitly into the rop layer rather than only trying
341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * to infer it. So, given that expectation, this code is
342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * written to deal with them.
343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        MakeState state = new MakeState(sz);
346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            DalvInsn insn = insns.get(i);
349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (insn instanceof LocalSnapshot) {
351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpecSet snapshot =
352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    ((LocalSnapshot) insn).getLocals();
353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                state.snapshot(insn.getAddress(), snapshot);
354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else if (insn instanceof LocalStart) {
355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec local = ((LocalStart) insn).getLocal();
356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                state.startLocal(insn.getAddress(), local);
357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else if (insn instanceof LocalEnd) {
358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec local = ((LocalEnd) insn).getLocal();
359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                state.endLocal(insn.getAddress(), local);
360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
363917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        LocalList result = state.finish();
364917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
365917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        if (DEBUG) {
366917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            debugVerify(result);
367917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
368917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
369917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        return result;
370917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
371917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
372917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
373917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Debugging helper that verifies the constraint that a list doesn't
374917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * contain any redundant local starts and that local ends that are
375917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * due to replacements are properly annotated.
376917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
377917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void debugVerify(LocalList locals) {
378917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        try {
379917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            debugVerify0(locals);
380917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        } catch (RuntimeException ex) {
381917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int sz = locals.size();
382917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < sz; i++) {
383917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.println(locals.get(i));
384917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
385917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            throw ex;
386917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
387917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
388917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
389917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
390917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
391917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Helper for {@link #debugVerify} which does most of the work.
392917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
393917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    private static void debugVerify0(LocalList locals) {
394917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        int sz = locals.size();
395917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        Entry[] active = new Entry[65536];
396917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
397917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        for (int i = 0; i < sz; i++) {
398917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Entry e = locals.get(i);
399917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int reg = e.getRegister();
400917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
401917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (e.isStart()) {
402917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Entry already = active[reg];
403917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
404917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if ((already != null) && e.matches(already)) {
405917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new RuntimeException("redundant start at " +
406917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            Integer.toHexString(e.getAddress()) + ": got " +
407917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            e + "; had " + already);
408917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
409917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
410917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                active[reg] = e;
411917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
412917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (active[reg] == null) {
413917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new RuntimeException("redundant end at " +
414917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            Integer.toHexString(e.getAddress()));
415917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
416917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
417917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int addr = e.getAddress();
418917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                boolean foundStart = false;
419917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
420917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                for (int j = i + 1; j < sz; j++) {
421917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    Entry test = locals.get(j);
422917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (test.getAddress() != addr) {
423917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        break;
424917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
425917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (test.getRegisterSpec().getReg() == reg) {
426917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        if (test.isStart()) {
427917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            if (e.getDisposition()
428917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    != Disposition.END_REPLACED) {
429917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                throw new RuntimeException(
430917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                        "improperly marked end at " +
431917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                        Integer.toHexString(addr));
432917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            }
433917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            foundStart = true;
434917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        } else {
435917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            throw new RuntimeException(
436917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    "redundant end at " +
437917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                    Integer.toHexString(addr));
438917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        }
439917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
440917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
441917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
442917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (!foundStart &&
443917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        (e.getDisposition() == Disposition.END_REPLACED)) {
444917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    throw new RuntimeException(
445917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            "improper end replacement claim at " +
446917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            Integer.toHexString(addr));
447917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
448917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
449917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                active[reg] = null;
450917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
451917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
452917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
453917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
454917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    /**
455917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     * Intermediate state when constructing a local list.
456917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul     */
457917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    public static class MakeState {
458917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code non-null;} result being collected */
459917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private final ArrayList<Entry> result;
460917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
461917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
462917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code >= 0;} running count of nulled result entries, to help with
463917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * sizing the final list
464917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
465917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private int nullResultCount;
466917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
467917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code null-ok;} current register mappings */
468917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private RegisterSpecSet regs;
469917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
470917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code null-ok;} result indices where local ends are stored */
471917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private int[] endIndices;
472917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
473917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /** {@code >= 0;} last address seen */
474917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private int lastAddress;
475917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
476917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
477917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Constructs an instance.
478917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
479917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public MakeState(int initialSize) {
480917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result = new ArrayList<Entry>(initialSize);
481917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            nullResultCount = 0;
482917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            regs = null;
483917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            endIndices = null;
484917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            lastAddress = 0;
485917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
486917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
487917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
488917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Checks the address and other vitals as a prerequisite to
489917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * further processing.
490917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
491917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} address about to be processed
492917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param reg {@code >= 0;} register number about to be processed
493917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
494917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private void aboutToProcess(int address, int reg) {
495917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean first = (endIndices == null);
496917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
497917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((address == lastAddress) && !first) {
498917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
499917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
500917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
501917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (address < lastAddress) {
502917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
503917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
504917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
505917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (first || (reg >= endIndices.length)) {
506917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
507917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * This is the first allocation of the state set and
508917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * index array, or we need to grow. (The latter doesn't
509917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * happen much; in fact, we have only ever observed
510917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * it happening in test cases, never in "real" code.)
511917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
512917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int newSz = reg + 1;
513917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpecSet newRegs = new RegisterSpecSet(newSz);
514917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int[] newEnds = new int[newSz];
515917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Arrays.fill(newEnds, -1);
516917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
517917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (!first) {
518917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    newRegs.putAll(regs);
519917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    System.arraycopy(endIndices, 0, newEnds, 0,
520917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            endIndices.length);
521917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
522917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
523917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                regs = newRegs;
524917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                endIndices = newEnds;
525917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
526917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
527917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
528917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
529917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Sets the local state at the given address to the given snapshot.
530917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * The first call on this instance must be to this method, so that
531917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * the register state can be properly sized.
532917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
533917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
534917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param specs {@code non-null;} spec set representing the locals
535917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
536917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void snapshot(int address, RegisterSpecSet specs) {
537917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (DEBUG) {
538917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.printf("%04x snapshot %s\n", address, specs);
539917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
540917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
541917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int sz = specs.getMaxSize();
542917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            aboutToProcess(address, sz - 1);
543917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
544917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < sz; i++) {
545917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec oldSpec = regs.get(i);
546917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec newSpec = filterSpec(specs.get(i));
547917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
548917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (oldSpec == null) {
549917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (newSpec != null) {
550917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        startLocal(address, newSpec);
551917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
552917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else if (newSpec == null) {
553917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    endLocal(address, oldSpec);
554917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                } else if (! newSpec.equalsUsingSimpleType(oldSpec)) {
555917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    endLocal(address, oldSpec);
556917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    startLocal(address, newSpec);
557917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
558917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
559917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
560917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (DEBUG) {
561917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.printf("%04x snapshot done\n", address);
562917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
563917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
564917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
565917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
566917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Starts a local at the given address.
567917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
568917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
569917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param startedLocal {@code non-null;} spec representing the
570917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * started local
571917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
572917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void startLocal(int address, RegisterSpec startedLocal) {
573917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (DEBUG) {
574917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.printf("%04x start %s\n", address, startedLocal);
575917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
576917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
577917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int regNum = startedLocal.getReg();
578917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
579917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            startedLocal = filterSpec(startedLocal);
580917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            aboutToProcess(address, regNum);
581917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
582917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec existingLocal = regs.get(regNum);
583917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
584917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (startedLocal.equalsUsingSimpleType(existingLocal)) {
585917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // Silently ignore a redundant start.
586917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
587917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
588917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
589917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            RegisterSpec movedLocal = regs.findMatchingLocal(startedLocal);
590917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (movedLocal != null) {
591917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
592917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * The same variable was moved from one register to another.
593917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * So add an end for its old location.
594917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
595917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                addOrUpdateEnd(address, Disposition.END_MOVED, movedLocal);
596917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
597917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
598917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int endAt = endIndices[regNum];
599917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
600917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (existingLocal != null) {
601917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
602917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * There is an existing (but non-matching) local.
603917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Add an explicit end for it.
604917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
605917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                add(address, Disposition.END_REPLACED, existingLocal);
606917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else if (endAt >= 0) {
607917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
608917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Look for an end local for the same register at the
609917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * same address. If found, then update it or delete
610917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * it, depending on whether or not it represents the
611917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * same variable as the one being started.
612917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
613917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Entry endEntry = result.get(endAt);
614917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (endEntry.getAddress() == address) {
615917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (endEntry.matches(startedLocal)) {
616917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        /*
617917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * There was already an end local for the same
618917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * variable at the same address. This turns
619917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * out to be superfluous, as we are starting
620917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * up the exact same local. This situation can
621917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * happen when a single local variable got
622917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * somehow "split up" during intermediate
623917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * processing. In any case, rather than represent
624917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * the end-then-start, just remove the old end.
625917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         */
626917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        result.set(endAt, null);
627917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        nullResultCount++;
628917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        regs.put(startedLocal);
629917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        endIndices[regNum] = -1;
630917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        return;
631917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    } else {
632917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        /*
633917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * There was a different variable ended at the
634917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * same address. Update it to indicate that
635917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * it was ended due to a replacement (rather than
636917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         * ending for no particular reason).
637917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                         */
638917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        endEntry = endEntry.withDisposition(
639917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                                Disposition.END_REPLACED);
640917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        result.set(endAt, endEntry);
641917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
642917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
643917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
644917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
645917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
646917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * The code above didn't find and remove an unnecessary
647917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * local end, so we now have to add one or more entries to
648917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * the output to capture the transition.
649917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
650917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
651917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
652917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * If the local just below (in the register set at reg-1)
653917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * is of category-2, then it is ended by this new start.
654917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
655917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (regNum > 0) {
656917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec justBelow = regs.get(regNum - 1);
657917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if ((justBelow != null) && justBelow.isCategory2()) {
658917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    addOrUpdateEnd(address,
659917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            Disposition.END_CLOBBERED_BY_NEXT,
660917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            justBelow);
661917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
662917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
663917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
664917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
665917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Similarly, if this local is category-2, then the local
666917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * just above (if any) is ended by the start now being
667917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * emitted.
668917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
669917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (startedLocal.isCategory2()) {
670917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec justAbove = regs.get(regNum + 1);
671917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (justAbove != null) {
672917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    addOrUpdateEnd(address,
673917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            Disposition.END_CLOBBERED_BY_PREV,
674917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            justAbove);
675917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
676917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
677917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
678917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
679917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * TODO: Add an end for the same local in a different reg,
680917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * if any (that is, if the local migrates from vX to vY,
681917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * we should note that as a local end in vX).
682917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
683917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
684917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            add(address, Disposition.START, startedLocal);
685917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
686917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
687917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
688917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Ends a local at the given address, using the disposition
689917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * {@code END_SIMPLY}.
690917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
691917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
692917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param endedLocal {@code non-null;} spec representing the
693917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local being ended
694917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
695917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void endLocal(int address, RegisterSpec endedLocal) {
696917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            endLocal(address, endedLocal, Disposition.END_SIMPLY);
697917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
698917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
699917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
700917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Ends a local at the given address.
701917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
702917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
703917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param endedLocal {@code non-null;} spec representing the
704917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local being ended
705917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param disposition reason for the end
706917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
707917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public void endLocal(int address, RegisterSpec endedLocal,
708917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Disposition disposition) {
709917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (DEBUG) {
710917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                System.err.printf("%04x end %s\n", address, endedLocal);
711917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
712917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
713917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int regNum = endedLocal.getReg();
714917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
715917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            endedLocal = filterSpec(endedLocal);
716917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            aboutToProcess(address, regNum);
717917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
718917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int endAt = endIndices[regNum];
719917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
720917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (endAt >= 0) {
721917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                /*
722917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * The local in the given register is already ended.
723917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 * Silently return without adding anything to the result.
724917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                 */
725917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
726917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
727917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
728917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Check for start and end at the same address.
729917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (checkForEmptyRange(address, endedLocal)) {
730917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return;
731917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
732917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
733917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            add(address, disposition, endedLocal);
734917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
735917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
736917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
737917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Helper for {@link #endLocal}, which handles the cases where
738917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and end local is issued at the same address as a start local
739917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * for the same register. If this case is found, then this
740917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * method will remove the start (as the local was never actually
741917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * active), update the {@link #endIndices} to be accurate, and
742917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * if needed update the newly-active end to reflect an altered
743917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * disposition.
744917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
745917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
746917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param endedLocal {@code non-null;} spec representing the
747917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local being ended
748917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code true} iff this method found the case in question
749917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * and adjusted things accordingly
750917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
751917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private boolean checkForEmptyRange(int address,
752917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec endedLocal) {
753917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int at = result.size() - 1;
754917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Entry entry;
755917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
756917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Look for a previous entry at the same address.
757917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (/*at*/; at >= 0; at--) {
758917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                entry = result.get(at);
759917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
760917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry == null) {
761917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    continue;
762917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
763917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
764917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.getAddress() != address) {
765917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    // We didn't find any match at the same address.
766917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    return false;
767917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
768917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
769917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.matches(endedLocal)) {
770917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
771917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
772917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
773917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
774917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
775917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * In fact, we found that the endedLocal had started at the
776917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * same address, so do all the requisite cleanup.
777917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
778917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
779917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            regs.remove(endedLocal);
780917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.set(at, null);
781917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            nullResultCount++;
782917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
783917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int regNum = endedLocal.getReg();
784917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            boolean found = false;
785917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            entry = null;
786917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
787917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            // Now look back further to update where the register ended.
788917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (at--; at >= 0; at--) {
789917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                entry = result.get(at);
790917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
791917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry == null) {
792917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    continue;
793917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
794917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
795917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.getRegisterSpec().getReg() == regNum) {
796917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    found = true;
797917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    break;
798917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
799917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
800917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
801917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (found) {
802917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // We found an end for the same register.
803917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                endIndices[regNum] = at;
804917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
805917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if (entry.getAddress() == address) {
806917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
807917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * It's still the same address, so update the
808917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * disposition.
809917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
810917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    result.set(at,
811917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                            entry.withDisposition(Disposition.END_SIMPLY));
812917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
813917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
814917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
815917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return true;
816917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
817917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
818917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
819917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Converts a given spec into the form acceptable for use in a
820917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * local list. This, in particular, transforms the "known
821917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * null" type into simply {@code Object}. This method needs to
822917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * be called for any spec that is on its way into a locals
823917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * list.
824917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
825917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * <p>This isn't necessarily the cleanest way to achieve the
826917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * goal of not representing known nulls in a locals list, but
827917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * it gets the job done.</p>
828917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
829917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param orig {@code null-ok;} the original spec
830917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code null-ok;} an appropriately modified spec, or the
831917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * original if nothing needs to be done
832917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
833917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private static RegisterSpec filterSpec(RegisterSpec orig) {
834917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if ((orig != null) && (orig.getType() == Type.KNOWN_NULL)) {
835917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return orig.withType(Type.OBJECT);
836917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
837917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
838917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return orig;
839917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
840917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
841917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
842917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Adds an entry to the result, updating the adjunct tables
843917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * accordingly.
844917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
845917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
846917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param disposition {@code non-null;} the disposition
847917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param spec {@code non-null;} spec representing the local
848917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
849917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private void add(int address, Disposition disposition,
850917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec spec) {
851917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int regNum = spec.getReg();
852917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
853917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            result.add(new Entry(address, disposition, spec));
854917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
855917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (disposition == Disposition.START) {
856917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                regs.put(spec);
857917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                endIndices[regNum] = -1;
858917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
859917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                regs.remove(spec);
860917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                endIndices[regNum] = result.size() - 1;
861917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
862917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
863917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
864917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
865917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Adds or updates an end local (changing its disposition). If
866917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * this would cause an empty range for a local, this instead
867917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * removes the local entirely.
868917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
869917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param address {@code >= 0;} the address
870917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param disposition {@code non-null;} the disposition
871917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @param spec {@code non-null;} spec representing the local
872917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
873917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        private void addOrUpdateEnd(int address, Disposition disposition,
874917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                RegisterSpec spec) {
875917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (disposition == Disposition.START) {
876917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                throw new RuntimeException("shouldn't happen");
877917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
878917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
879917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int regNum = spec.getReg();
880917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int endAt = endIndices[regNum];
881917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
882917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (endAt >= 0) {
883917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                // There is a previous end.
884917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                Entry endEntry = result.get(endAt);
885917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                if ((endEntry.getAddress() == address) &&
886917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        endEntry.getRegisterSpec().equals(spec)) {
887917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    /*
888917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * The end is for the right address and variable, so
889917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     * update it.
890917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                     */
891917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    result.set(endAt, endEntry.withDisposition(disposition));
892917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    regs.remove(spec); // TODO: Is this line superfluous?
893917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    return;
894917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
895917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
896917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
897917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            endLocal(address, spec, disposition);
898917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
899917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
900917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        /**
901917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * Finishes processing altogether and gets the result.
902917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         *
903917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         * @return {@code non-null;} the result list
904917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul         */
905917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        public LocalList finish() {
906917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            aboutToProcess(Integer.MAX_VALUE, 0);
907917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
908917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int resultSz = result.size();
909917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            int finalSz = resultSz - nullResultCount;
910917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
911917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (finalSz == 0) {
912917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                return EMPTY;
913917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
914917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
915917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            /*
916917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * Collect an array of only the non-null entries, and then
917917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * sort it to get a consistent order for everything: Local
918917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * ends and starts for a given address could come in any
919917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * order, but we want ends before starts as well as
920917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             * registers in order (within ends or starts).
921917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul             */
922917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
923917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Entry[] resultArr = new Entry[finalSz];
924917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
925917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            if (resultSz == finalSz) {
926917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                result.toArray(resultArr);
927917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            } else {
928917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                int at = 0;
929917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                for (Entry e : result) {
930917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    if (e != null) {
931917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                        resultArr[at++] = e;
932917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                    }
933917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                }
934917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
935917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
936917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            Arrays.sort(resultArr);
937917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
938917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            LocalList resultList = new LocalList(finalSz);
939917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
940917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            for (int i = 0; i < finalSz; i++) {
941917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul                resultList.set(i, resultArr[i]);
942917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            }
943917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul
944917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            resultList.setImmutable();
945917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul            return resultList;
946917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul        }
947917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul    }
948917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul}
949