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