diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/util/TryListBuilder.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/util/TryListBuilder.java index ae20f902..e8c256cd 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/util/TryListBuilder.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/util/TryListBuilder.java @@ -39,6 +39,7 @@ import org.jf.dexlib2.immutable.ImmutableExceptionHandler; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; @@ -125,6 +126,17 @@ public class TryListBuilder return newTryBlock; } + public void delete() { + next.prev = prev; + prev.next = next; + } + + public void mergeNext() { + //assert next.startCodeAddress == this.endCodeAddress; + this.endCodeAddress = next.endCodeAddress; + next.delete(); + } + public void append(@Nonnull MutableTryBlock tryBlock) { next.prev = tryBlock; tryBlock.next = next; @@ -296,18 +308,48 @@ public class TryListBuilder public List getTryBlocks() { return Lists.newArrayList(new Iterator() { - private MutableTryBlock tryBlock = listStart; + // The next TryBlock to return. This has already been merged, if needed. + @Nullable private MutableTryBlock next; + + { + next = listStart; + next = readNextItem(); + } + + /** + * Read the item that comes after the current value of the next field. + * @return The next item, or null if there is no next item + */ + @Nullable protected MutableTryBlock readNextItem() { + // We can assume that next is not null + MutableTryBlock ret = next.next; + + if (ret == listEnd) { + return null; + } + + while (ret.next != listEnd) { + if (ret.endCodeAddress == ret.next.startCodeAddress && + ret.getExceptionHandlers().equals(ret.next.getExceptionHandlers())) { + ret.mergeNext(); + } else { + break; + } + } + return ret; + } @Override public boolean hasNext() { - return tryBlock.next != listEnd; + return next != null; } @Override public TryBlock next() { if (!hasNext()) { throw new NoSuchElementException(); } - tryBlock = tryBlock.next; - return tryBlock; + TryBlock ret = next; + next = readNextItem(); + return ret; } @Override public void remove() { diff --git a/dexlib2/src/test/java/org/jf/dexlib2/writer/util/TryListBuilderTest.java b/dexlib2/src/test/java/org/jf/dexlib2/writer/util/TryListBuilderTest.java index 306e300e..aa5e7519 100644 --- a/dexlib2/src/test/java/org/jf/dexlib2/writer/util/TryListBuilderTest.java +++ b/dexlib2/src/test/java/org/jf/dexlib2/writer/util/TryListBuilderTest.java @@ -409,13 +409,7 @@ public class TryListBuilderTest { List tryBlocks = tlb.getTryBlocks(); List expected = ImmutableList.of( - new ImmutableTryBlock(0, 5, - ImmutableList.of( - new ImmutableExceptionHandler("LException1;", 5))), - new ImmutableTryBlock(5, 5, - ImmutableList.of( - new ImmutableExceptionHandler("LException1;", 5))), - new ImmutableTryBlock(10, 5, + new ImmutableTryBlock(0, 15, ImmutableList.of( new ImmutableExceptionHandler("LException1;", 5)))); @@ -517,13 +511,7 @@ public class TryListBuilderTest { List tryBlocks = tlb.getTryBlocks(); List expected = ImmutableList.of( - new ImmutableTryBlock(0, 5, - ImmutableList.of( - new ImmutableExceptionHandler(null, 5))), - new ImmutableTryBlock(5, 5, - ImmutableList.of( - new ImmutableExceptionHandler(null, 5))), - new ImmutableTryBlock(10, 5, + new ImmutableTryBlock(0, 15, ImmutableList.of( new ImmutableExceptionHandler(null, 5)))); @@ -542,4 +530,37 @@ public class TryListBuilderTest { } Assert.fail(); } + + @Test + public void testHandlerMerge_MergeSame() { + TryListBuilder tlb = new TryListBuilder(); + + tlb.addHandler(null, 0, 15, 6); + tlb.addHandler("LException1;", 10, 20, 5); + tlb.addHandler("LException1;", 20, 30, 5); + tlb.addHandler(null, 25, 40, 6); + + List tryBlocks = tlb.getTryBlocks(); + + List expected = ImmutableList.of( + new ImmutableTryBlock(0, 10, + ImmutableList.of( + new ImmutableExceptionHandler(null, 6))), + new ImmutableTryBlock(10, 5, + ImmutableList.of( + new ImmutableExceptionHandler(null, 6), + new ImmutableExceptionHandler("LException1;", 5))), + new ImmutableTryBlock(15, 10, + ImmutableList.of( + new ImmutableExceptionHandler("LException1;", 5))), + new ImmutableTryBlock(25, 5, + ImmutableList.of( + new ImmutableExceptionHandler("LException1;", 5), + new ImmutableExceptionHandler(null, 6))), + new ImmutableTryBlock(30, 10, + ImmutableList.of( + new ImmutableExceptionHandler(null, 6)))); + + Assert.assertEquals(expected, tryBlocks); + } }