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 @Nonnull
@Override @Override
public List<? extends DebugItem> getDebugItems() { public Iterable<? extends DebugItem> getDebugItems() {
final int debugInfoOffset = dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET); final int debugInfoOffset = dexBuf.readSmallUint(codeOffset + DEBUG_OFFSET_OFFSET);
if (debugInfoOffset > 0) { if (debugInfoOffset > 0) {
return new DebugItemList(dexBuf, debugInfoOffset, method); return new DebugItemList(dexBuf, debugInfoOffset, method);

View File

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

View File

@ -41,5 +41,5 @@ public interface MethodImplementation {
int getRegisterCount(); int getRegisterCount();
@Nonnull List<? extends Instruction> getInstructions(); @Nonnull List<? extends Instruction> getInstructions();
@Nonnull List<? extends TryBlock> getTryBlocks(); @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, public ImmutableMethodImplementation(int registerCount,
@Nullable List<? extends Instruction> instructions, @Nullable List<? extends Instruction> instructions,
@Nullable List<? extends TryBlock> tryBlocks, @Nullable List<? extends TryBlock> tryBlocks,
@Nullable List<? extends DebugItem> debugItems) { @Nullable Iterable<? extends DebugItem> debugItems) {
this.registerCount = registerCount; this.registerCount = registerCount;
this.instructions = ImmutableInstruction.immutableListOf(instructions); this.instructions = ImmutableInstruction.immutableListOf(instructions);
this.tryBlocks = ImmutableTryBlock.immutableListOf(tryBlocks); this.tryBlocks = ImmutableTryBlock.immutableListOf(tryBlocks);

View File

@ -77,7 +77,7 @@ public abstract class ImmutableDebugItem implements DebugItem {
@Override public int getCodeAddress() { return codeAddress; } @Override public int getCodeAddress() { return codeAddress; }
@Nonnull @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); return CONVERTER.convert(list);
} }

View File

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