Use an iterable rather than a list for debug items

This commit is contained in:
Ben Gruver 2012-10-27 22:39:07 -07:00
parent 6dd026a0bd
commit 08840432d4
6 changed files with 53 additions and 47 deletions

View File

@ -109,7 +109,7 @@ public class DexBackedMethodImplementation implements MethodImplementation {
@Nonnull
@Override
public List<? extends DebugItem> getDebugItems() {
public Iterable<? extends DebugItem> getDebugItems() {
final int debugInfoOffset = dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET);
if (debugInfoOffset > 0) {
return new DebugItemList(dexBuf, debugInfoOffset, method);

View File

@ -46,9 +46,10 @@ import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
public class DebugItemList implements Iterable<DebugItem> {
@Nonnull public final DexBuffer dexBuf;
private final int debugInfoOffset;
@Nonnull private final Method method;
@ -75,7 +76,7 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
@Nonnull
@Override
public Iterator listIterator() {
public Iterator<DebugItem> iterator() {
DexReader initialReader = dexBuf.readerAt(debugInfoOffset);
// TODO: this unsigned value could legitimally be > MAX_INT
final int lineNumberStart = initialReader.readSmallUleb128();
@ -89,7 +90,7 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
// information, the method obviously has an implementation.
VariableSizeList<? extends MethodParameter> parameters =
(VariableSizeList<? extends MethodParameter>)method.getParameters();
VariableSizeList<? extends MethodParameter>.Iterator parameterIterator = parameters.listIterator();
final VariableSizeList<? extends MethodParameter>.Iterator parameterIterator = parameters.listIterator();
{ // local scope for i
int i=0;
@ -113,23 +114,25 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
}
}
return new Iterator(dexBuf, parameterIterator.getReaderOffset()) {
return new Iterator<DebugItem>() {
@Nonnull private DexReader reader = dexBuf.readerAt(parameterIterator.getReaderOffset());
private boolean finished = false;
private int codeAddress = 0;
private int lineNumber = lineNumberStart;
@Nonnull
@Override
protected DebugItem readItem(@Nonnull DexReader reader, int index) {
@Nullable private DebugItem nextItem;
@Nullable
protected DebugItem readItem() {
if (finished) {
throw new NoSuchElementException();
return null;
}
while (true) {
int next = reader.readUbyte();
switch (next) {
case DebugItemType.END_SEQUENCE: {
finished = true;
throw new NoSuchElementException();
return null;
}
case DebugItemType.ADVANCE_PC: {
int addressDiff = reader.readSmallUleb128();
@ -209,19 +212,36 @@ public class DebugItemList extends VariableSizeListWithContext<DebugItem> {
}
@Override
protected void skipItem(@Nonnull DexReader reader, int index) {
super.skipItem(reader, index);
public boolean hasNext() {
if (finished || nextItem != null) {
return false;
}
nextItem = readItem();
return nextItem != null;
}
@Nonnull
@Override
public DebugItem next() {
if (finished) {
throw new NoSuchElementException();
}
if (nextItem == null) {
DebugItem ret = readItem();
if (ret == null) {
throw new NoSuchElementException();
}
return ret;
}
DebugItem ret = nextItem;
nextItem = null;
return ret;
}
@Override
protected void checkBounds(int index) {
// skip the bounds check here. We'll throw NoSuchElementException directly from readItem
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public int size() {
throw new UnsupportedOperationException();
}
}

View File

@ -41,5 +41,5 @@ public interface MethodImplementation {
int getRegisterCount();
@Nonnull List<? extends Instruction> getInstructions();
@Nonnull List<? extends TryBlock> getTryBlocks();
@Nonnull List<? extends DebugItem> getDebugItems();
@Nonnull Iterable<? extends DebugItem> getDebugItems();
}

View File

@ -53,7 +53,7 @@ public class ImmutableMethodImplementation implements MethodImplementation {
public ImmutableMethodImplementation(int registerCount,
@Nullable List<? extends Instruction> instructions,
@Nullable List<? extends TryBlock> tryBlocks,
@Nullable List<? extends DebugItem> debugItems) {
@Nullable Iterable<? extends DebugItem> debugItems) {
this.registerCount = registerCount;
this.instructions = ImmutableInstruction.immutableListOf(instructions);
this.tryBlocks = ImmutableTryBlock.immutableListOf(tryBlocks);

View File

@ -77,7 +77,7 @@ public abstract class ImmutableDebugItem implements DebugItem {
@Override public int getCodeAddress() { return codeAddress; }
@Nonnull
public static ImmutableList<ImmutableDebugItem> immutableListOf(@Nullable List<? extends DebugItem> list) {
public static ImmutableList<ImmutableDebugItem> immutableListOf(@Nullable Iterable<? extends DebugItem> list) {
return CONVERTER.convert(list);
}

View File

@ -36,7 +36,6 @@ import com.google.common.collect.ImmutableList;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.List;
/**
* This class converts a list of items to an immutable list of immutable items
@ -51,18 +50,18 @@ public abstract class ImmutableListConverter<ImmutableItem, Item> {
* If the provided list is already an ImmutableList of ImmutableItems, then the list is not copied and is returned
* as-is. If the list is null, an empty ImmutableList will be returned
*
* @param list The list of items to convert.
* @param iterable The iterable of items to convert.
* @return An ImmutableList of ImmutableItem. If list is null, an empty list will be returned.
*/
@Nonnull
public ImmutableList<ImmutableItem> convert(@Nullable final List<? extends Item> list) {
if (list == null) {
public ImmutableList<ImmutableItem> convert(@Nullable final Iterable<? extends Item> iterable) {
if (iterable == null) {
return ImmutableList.of();
}
boolean needsCopy = false;
if (list instanceof ImmutableList) {
for (Item element: list) {
if (iterable instanceof ImmutableList) {
for (Item element: iterable) {
if (isImmutable(element)) {
needsCopy = true;
break;
@ -73,28 +72,15 @@ public abstract class ImmutableListConverter<ImmutableItem, Item> {
}
if (!needsCopy) {
return (ImmutableList<ImmutableItem>)list;
return (ImmutableList<ImmutableItem>)iterable;
}
final Iterator<? extends Item> iter = iterable.iterator();
return ImmutableList.copyOf(new Iterator<ImmutableItem>() {
protected int index = 0;
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public ImmutableItem next() {
ImmutableItem item = makeImmutable(list.get(index));
index++;
return item;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override public boolean hasNext() { return iter.hasNext(); }
@Override public ImmutableItem next() { return makeImmutable(iter.next()); }
@Override public void remove() { iter.remove(); }
});
}