1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dexgen.rop; 18 19import com.android.dexgen.util.FixedSizeList; 20 21/** 22 * List of "line number" entries, which are the contents of 23 * {@code LineNumberTable} attributes. 24 */ 25public final class LineNumberList extends FixedSizeList { 26 /** {@code non-null;} zero-size instance */ 27 public static final LineNumberList EMPTY = new LineNumberList(0); 28 29 /** 30 * Returns an instance which is the concatenation of the two given 31 * instances. 32 * 33 * @param list1 {@code non-null;} first instance 34 * @param list2 {@code non-null;} second instance 35 * @return {@code non-null;} combined instance 36 */ 37 public static LineNumberList concat(LineNumberList list1, 38 LineNumberList list2) { 39 if (list1 == EMPTY) { 40 // easy case 41 return list2; 42 } 43 44 int sz1 = list1.size(); 45 int sz2 = list2.size(); 46 LineNumberList result = new LineNumberList(sz1 + sz2); 47 48 for (int i = 0; i < sz1; i++) { 49 result.set(i, list1.get(i)); 50 } 51 52 for (int i = 0; i < sz2; i++) { 53 result.set(sz1 + i, list2.get(i)); 54 } 55 56 return result; 57 } 58 59 /** 60 * Constructs an instance. 61 * 62 * @param count the number of elements to be in the list 63 */ 64 public LineNumberList(int count) { 65 super(count); 66 } 67 68 /** 69 * Gets the indicated item. 70 * 71 * @param n {@code >= 0;} which item 72 * @return {@code null-ok;} the indicated item 73 */ 74 public Item get(int n) { 75 return (Item) get0(n); 76 } 77 78 /** 79 * Sets the item at the given index. 80 * 81 * @param n {@code >= 0, < size();} which element 82 * @param item {@code non-null;} the item 83 */ 84 public void set(int n, Item item) { 85 if (item == null) { 86 throw new NullPointerException("item == null"); 87 } 88 89 set0(n, item); 90 } 91 92 /** 93 * Sets the item at the given index. 94 * 95 * @param n {@code >= 0, < size();} which element 96 * @param startPc {@code >= 0;} start pc of this item 97 * @param lineNumber {@code >= 0;} corresponding line number 98 */ 99 public void set(int n, int startPc, int lineNumber) { 100 set0(n, new Item(startPc, lineNumber)); 101 } 102 103 /** 104 * Gets the line number associated with the given address. 105 * 106 * @param pc {@code >= 0;} the address to look up 107 * @return {@code >= -1;} the associated line number, or {@code -1} if 108 * none is known 109 */ 110 public int pcToLine(int pc) { 111 /* 112 * Line number entries don't have to appear in any particular 113 * order, so we have to do a linear search. TODO: If 114 * this turns out to be a bottleneck, consider sorting the 115 * list prior to use. 116 */ 117 int sz = size(); 118 int bestPc = -1; 119 int bestLine = -1; 120 121 for (int i = 0; i < sz; i++) { 122 Item one = get(i); 123 int onePc = one.getStartPc(); 124 if ((onePc <= pc) && (onePc > bestPc)) { 125 bestPc = onePc; 126 bestLine = one.getLineNumber(); 127 if (bestPc == pc) { 128 // We can't do better than this 129 break; 130 } 131 } 132 } 133 134 return bestLine; 135 } 136 137 /** 138 * Item in a line number table. 139 */ 140 public static class Item { 141 /** {@code >= 0;} start pc of this item */ 142 private final int startPc; 143 144 /** {@code >= 0;} corresponding line number */ 145 private final int lineNumber; 146 147 /** 148 * Constructs an instance. 149 * 150 * @param startPc {@code >= 0;} start pc of this item 151 * @param lineNumber {@code >= 0;} corresponding line number 152 */ 153 public Item(int startPc, int lineNumber) { 154 if (startPc < 0) { 155 throw new IllegalArgumentException("startPc < 0"); 156 } 157 158 if (lineNumber < 0) { 159 throw new IllegalArgumentException("lineNumber < 0"); 160 } 161 162 this.startPc = startPc; 163 this.lineNumber = lineNumber; 164 } 165 166 /** 167 * Gets the start pc of this item. 168 * 169 * @return the start pc 170 */ 171 public int getStartPc() { 172 return startPc; 173 } 174 175 /** 176 * Gets the line number of this item. 177 * 178 * @return the line number 179 */ 180 public int getLineNumber() { 181 return lineNumber; 182 } 183 } 184} 185