| /* |
| * 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; |
| } |
| } |
| } |