Home | History | Annotate | Download | only in code
      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 
     17 package com.android.dx.cf.code;
     18 
     19 import com.android.dx.util.FixedSizeList;
     20 
     21 /**
     22  * List of "line number" entries, which are the contents of
     23  * {@code LineNumberTable} attributes.
     24  */
     25 public 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