LocalList.java revision 579d7739c53a2707ad711a2d2cae46d7d782f06
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