|  | // Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  | package com.android.tools.r8.graph; | 
|  |  | 
|  | import static org.junit.Assert.assertEquals; | 
|  | import static org.junit.Assert.assertTrue; | 
|  |  | 
|  | import com.android.tools.r8.graph.DexDebugEvent.AdvancePC; | 
|  | import com.android.tools.r8.graph.DexDebugEvent.Default; | 
|  | import com.android.tools.r8.ir.code.Position; | 
|  | import java.util.ArrayList; | 
|  | import java.util.List; | 
|  | import java.util.function.Consumer; | 
|  | import org.junit.Test; | 
|  |  | 
|  | public class DexDebugEventsTest { | 
|  |  | 
|  | static final DexItemFactory factory = new DexItemFactory(); | 
|  | static final DexMethod method = factory.createMethod( | 
|  | factory.objectDescriptor, | 
|  | factory.createString("foo"), | 
|  | factory.voidDescriptor, | 
|  | DexString.EMPTY_ARRAY); | 
|  |  | 
|  | @Test | 
|  | public void testSpecialOpcodeRepresentation() { | 
|  | { | 
|  | // Smallest numeric opcode. | 
|  | Default minDefault = new Default(0x0a); | 
|  | assertEquals(0, minDefault.getPCDelta()); | 
|  | assertEquals(-4, minDefault.getLineDelta()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Largest numeric opcode. | 
|  | Default maxDefault = new Default(0xff); | 
|  | assertEquals(16, maxDefault.getPCDelta()); | 
|  | assertEquals(1, maxDefault.getLineDelta()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // PC range of 16, smallest value for line is -4 delta. | 
|  | Default maxPcDefault = new Default(0xff - 5); | 
|  | assertEquals(16, maxPcDefault.getPCDelta()); | 
|  | assertEquals(-4, maxPcDefault.getLineDelta()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // Maximum line range is 15 points ranging from -4 to 10. | 
|  | Default maxLineDefault = new Default(0x0a + 14); | 
|  | assertEquals(0, maxLineDefault.getPCDelta()); | 
|  | assertEquals(10, maxLineDefault.getLineDelta()); | 
|  | } | 
|  |  | 
|  | // For a PC advance of 16, only the line range -4 to 1 can be represented. | 
|  | for (int i = 0; i < 6; i++) { | 
|  | Default maxPcAndRangeDefault = new Default(0xff - i); | 
|  | assertEquals(16, maxPcAndRangeDefault.getPCDelta()); | 
|  | assertEquals(1 - i, maxPcAndRangeDefault.getLineDelta()); | 
|  | } | 
|  |  | 
|  | { | 
|  | // For a line advance of 10 the max PC is 15. | 
|  | Default maxPcIfUsingMaxLineDefault = new Default(0xff - 6); | 
|  | assertEquals(15, maxPcIfUsingMaxLineDefault.getPCDelta()); | 
|  | assertEquals(10, maxPcIfUsingMaxLineDefault.getLineDelta()); | 
|  | } | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testMaxPcMinLine() { | 
|  | testAdvancement(0, 16, 5, 1, events -> { | 
|  | assertEquals(1, events.size()); | 
|  | assertTrue(events.get(0) instanceof Default); | 
|  | Default event = (Default) events.get(0); | 
|  | assertEquals(16, event.getPCDelta()); | 
|  | assertEquals(-4, event.getLineDelta()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testMaxPcRemainingLine() { | 
|  | testAdvancement(0, 16, 1, 2, events -> { | 
|  | assertEquals(1, events.size()); | 
|  | assertTrue(events.get(0) instanceof Default); | 
|  | Default event = (Default) events.get(0); | 
|  | assertEquals(16, event.getPCDelta()); | 
|  | assertEquals(1, event.getLineDelta()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testMaxPcPlusOne() { | 
|  | testAdvancement(0, 17, 1, 2, events -> { | 
|  | assertEquals(2, events.size()); | 
|  | assertTrue(events.get(0) instanceof AdvancePC); | 
|  | assertTrue(events.get(1) instanceof Default); | 
|  | AdvancePC advancePC = (AdvancePC) events.get(0); | 
|  | Default aDefault = (Default) events.get(1); | 
|  | assertEquals(17, advancePC.delta + aDefault.getPCDelta()); | 
|  | assertEquals(1, aDefault.getLineDelta()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testMaxPcMaxLine() { | 
|  | // If line delta is larger that 1 then there is not room for a pc delta of 16. | 
|  | testAdvancement(0, 16, 1, 11, events -> { | 
|  | assertEquals(2, events.size()); | 
|  | assertTrue(events.get(0) instanceof AdvancePC); | 
|  | assertTrue(events.get(1) instanceof Default); | 
|  | AdvancePC advancePC = (AdvancePC) events.get(0); | 
|  | Default aDefault = (Default) events.get(1); | 
|  | assertEquals(16, advancePC.delta + aDefault.getPCDelta()); | 
|  | assertEquals(10, aDefault.getLineDelta()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testMaxLineRemainingPc() { | 
|  | testAdvancement(0, 15, 1, 11, events -> { | 
|  | assertEquals(1, events.size()); | 
|  | assertTrue(events.get(0) instanceof Default); | 
|  | Default event = (Default) events.get(0); | 
|  | assertEquals(15, event.getPCDelta()); | 
|  | assertEquals(10, event.getLineDelta()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | private void testAdvancement( | 
|  | int pc, int nextPc, int line, int nextLine, Consumer<List<DexDebugEvent>> consumer) { | 
|  | List<DexDebugEvent> events = new ArrayList<>(); | 
|  | DexDebugEventBuilder.emitAdvancementEvents( | 
|  | pc, | 
|  | new Position(line, null, method, null), | 
|  | nextPc, | 
|  | new Position(nextLine, null, method, null), | 
|  | events, | 
|  | factory); | 
|  | consumer.accept(events); | 
|  | } | 
|  | } |