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.dexgen.dex.code;
18 
19 import com.android.dexgen.rop.code.SourcePosition;
20 import com.android.dexgen.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      */
make(DalvInsnList insns, int howMuch)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      */
PositionList(int size)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      */
get(int n)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      */
set(int n, Entry entry)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          */
Entry(int address, SourcePosition position)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          */
getAddress()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          */
getPosition()188         public SourcePosition getPosition() {
189             return position;
190         }
191     }
192 }
193