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