blob: 1e07e46693012a99f9fbd7f3fd5231664e36cd82 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.dx.dex.code;
import com.android.dx.rop.code.SourcePosition;
import com.android.dx.util.FixedSizeList;
/**
* List of source position entries. This class includes a utility
* method to extract an instance out of a {@link DalvInsnList}.
*/
public final class PositionList extends FixedSizeList {
/** {@code non-null;} empty instance */
public static final PositionList EMPTY = new PositionList(0);
/**
* constant for {@link #make} to indicate that no actual position
* information should be returned
*/
public static final int NONE = 1;
/**
* constant for {@link #make} to indicate that only line number
* transitions should be returned
*/
public static final int LINES = 2;
/**
* constant for {@link #make} to indicate that only "important" position
* information should be returned. This includes block starts and
* instructions that might throw.
*/
public static final int IMPORTANT = 3;
/**
* Extracts and returns the source position information out of an
* instruction list.
*
* @param insns {@code non-null;} instructions to convert
* @param howMuch how much information should be included; one of the
* static constants defined by this class
* @return {@code non-null;} the positions list
*/
public static PositionList make(DalvInsnList insns, int howMuch) {
switch (howMuch) {
case NONE: {
return EMPTY;
}
case LINES:
case IMPORTANT: {
// Valid.
break;
}
default: {
throw new IllegalArgumentException("bogus howMuch");
}
}
SourcePosition noInfo = SourcePosition.NO_INFO;
SourcePosition cur = noInfo;
int sz = insns.size();
PositionList.Entry[] arr = new PositionList.Entry[sz];
boolean lastWasTarget = false;
int at = 0;
for (int i = 0; i < sz; i++) {
DalvInsn insn = insns.get(i);
if (insn instanceof CodeAddress) {
lastWasTarget = true;;
continue;
}
SourcePosition pos = insn.getPosition();
if (pos.equals(noInfo) || pos.sameLine(cur)) {
continue;
}
if ((howMuch == IMPORTANT) && !lastWasTarget) {
continue;
}
cur = pos;
arr[at] = new PositionList.Entry(insn.getAddress(), pos);
at++;
lastWasTarget = false;
}
PositionList result = new PositionList(at);
for (int i = 0; i < at; i++) {
result.set(i, arr[i]);
}
result.setImmutable();
return result;
}
/**
* Constructs an instance. All indices initially contain {@code null}.
*
* @param size {@code >= 0;} the size of the list
*/
public PositionList(int size) {
super(size);
}
/**
* Gets the element at the given index. It is an error to call
* this with the index for an element which was never set; if you
* do that, this will throw {@code NullPointerException}.
*
* @param n {@code >= 0, < size();} which index
* @return {@code non-null;} element at that index
*/
public Entry get(int n) {
return (Entry) get0(n);
}
/**
* Sets the entry at the given index.
*
* @param n {@code >= 0, < size();} which index
* @param entry {@code non-null;} the entry to set at {@code n}
*/
public void set(int n, Entry entry) {
set0(n, entry);
}
/**
* Entry in a position list.
*/
public static class Entry {
/** {@code >= 0;} address of this entry */
private final int address;
/** {@code non-null;} corresponding source position information */
private final SourcePosition position;
/**
* Constructs an instance.
*
* @param address {@code >= 0;} address of this entry
* @param position {@code non-null;} corresponding source position information
*/
public Entry (int address, SourcePosition position) {
if (address < 0) {
throw new IllegalArgumentException("address < 0");
}
if (position == null) {
throw new NullPointerException("position == null");
}
this.address = address;
this.position = position;
}
/**
* Gets the address.
*
* @return {@code >= 0;} the address
*/
public int getAddress() {
return address;
}
/**
* Gets the source position information.
*
* @return {@code non-null;} the position information
*/
public SourcePosition getPosition() {
return position;
}
}
}