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.dex.code;
     18 
     19 import com.android.dx.rop.code.SourcePosition;
     20 import com.android.dx.util.FixedSizeList;
     21 
     22 /**
     23  * List of source position entries. This class includes a utility
     24  * method to extract an instance out of a {@link DalvInsnList}.
     25  */
     26 public final class PositionList extends FixedSizeList {
     27     /** {@code non-null;} empty instance */
     28     public static final PositionList EMPTY = new PositionList(0);
     29 
     30     /**
     31      * constant for {@link #make} to indicate that no actual position
     32      * information should be returned
     33      */
     34     public static final int NONE = 1;
     35 
     36     /**
     37      * constant for {@link #make} to indicate that only line number
     38      * transitions should be returned
     39      */
     40     public static final int LINES = 2;
     41 
     42     /**
     43      * constant for {@link #make} to indicate that only "important" position
     44      * information should be returned. This includes block starts and
     45      * instructions that might throw.
     46      */
     47     public static final int IMPORTANT = 3;
     48 
     49     /**
     50      * Extracts and returns the source position information out of an
     51      * instruction list.
     52      *
     53      * @param insns {@code non-null;} instructions to convert
     54      * @param howMuch how much information should be included; one of the
     55      * static constants defined by this class
     56      * @return {@code non-null;} the positions list
     57      */
     58     public static PositionList make(DalvInsnList insns, int howMuch) {
     59         switch (howMuch) {
     60             case NONE: {
     61                 return EMPTY;
     62             }
     63             case LINES:
     64             case IMPORTANT: {
     65                 // Valid.
     66                 break;
     67             }
     68             default: {
     69                 throw new IllegalArgumentException("bogus howMuch");
     70             }
     71         }
     72 
     73         SourcePosition noInfo = SourcePosition.NO_INFO;
     74         SourcePosition cur = noInfo;
     75         int sz = insns.size();
     76         PositionList.Entry[] arr = new PositionList.Entry[sz];
     77         boolean lastWasTarget = false;
     78         int at = 0;
     79 
     80         for (int i = 0; i < sz; i++) {
     81             DalvInsn insn = insns.get(i);
     82 
     83             if (insn instanceof CodeAddress) {
     84                 lastWasTarget = true;;
     85                 continue;
     86             }
     87 
     88             SourcePosition pos = insn.getPosition();
     89 
     90             if (pos.equals(noInfo) || pos.sameLine(cur)) {
     91                 continue;
     92             }
     93 
     94             if ((howMuch == IMPORTANT) && !lastWasTarget) {
     95                 continue;
     96             }
     97 
     98             cur = pos;
     99             arr[at] = new PositionList.Entry(insn.getAddress(), pos);
    100             at++;
    101 
    102             lastWasTarget = false;
    103         }
    104 
    105         PositionList result = new PositionList(at);
    106         for (int i = 0; i < at; i++) {
    107             result.set(i, arr[i]);
    108         }
    109 
    110         result.setImmutable();
    111         return result;
    112     }
    113 
    114     /**
    115      * Constructs an instance. All indices initially contain {@code null}.
    116      *
    117      * @param size {@code >= 0;} the size of the list
    118      */
    119     public PositionList(int size) {
    120         super(size);
    121     }
    122 
    123     /**
    124      * Gets the element at the given index. It is an error to call
    125      * this with the index for an element which was never set; if you
    126      * do that, this will throw {@code NullPointerException}.
    127      *
    128      * @param n {@code >= 0, < size();} which index
    129      * @return {@code non-null;} element at that index
    130      */
    131     public Entry get(int n) {
    132         return (Entry) get0(n);
    133     }
    134 
    135     /**
    136      * Sets the entry at the given index.
    137      *
    138      * @param n {@code >= 0, < size();} which index
    139      * @param entry {@code non-null;} the entry to set at {@code n}
    140      */
    141     public void set(int n, Entry entry) {
    142         set0(n, entry);
    143     }
    144 
    145     /**
    146      * Entry in a position list.
    147      */
    148     public static class Entry {
    149         /** {@code >= 0;} address of this entry */
    150         private final int address;
    151 
    152         /** {@code non-null;} corresponding source position information */
    153         private final SourcePosition position;
    154 
    155         /**
    156          * Constructs an instance.
    157          *
    158          * @param address {@code >= 0;} address of this entry
    159          * @param position {@code non-null;} corresponding source position information
    160          */
    161         public Entry (int address, SourcePosition position) {
    162             if (address < 0) {
    163                 throw new IllegalArgumentException("address < 0");
    164             }
    165 
    166             if (position == null) {
    167                 throw new NullPointerException("position == null");
    168             }
    169 
    170             this.address = address;
    171             this.position = position;
    172         }
    173 
    174         /**
    175          * Gets the address.
    176          *
    177          * @return {@code >= 0;} the address
    178          */
    179         public int getAddress() {
    180             return address;
    181         }
    182 
    183         /**
    184          * Gets the source position information.
    185          *
    186          * @return {@code non-null;} the position information
    187          */
    188         public SourcePosition getPosition() {
    189             return position;
    190         }
    191     }
    192 }
    193