|  | // Copyright (c) 2017, 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.debug; | 
|  |  | 
|  | import static org.hamcrest.core.IsNot.not; | 
|  |  | 
|  | import com.android.tools.r8.ToolHelper; | 
|  | import com.android.tools.r8.ToolHelper.DexVm; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import java.util.Collection; | 
|  | import org.junit.Assume; | 
|  | import org.junit.Test; | 
|  | import org.junit.runner.RunWith; | 
|  | import org.junit.runners.Parameterized; | 
|  |  | 
|  | /** Test single stepping behaviour of synchronized blocks. */ | 
|  | @RunWith(Parameterized.class) | 
|  | public class SynchronizedBlockTest extends DebugTestBase { | 
|  |  | 
|  | public static final String CLASS = "SynchronizedBlock"; | 
|  | public static final String FILE = "SynchronizedBlock.java"; | 
|  |  | 
|  | private final String name; | 
|  | private final DebugTestConfig config; | 
|  |  | 
|  | @Parameterized.Parameters(name = "{0}") | 
|  | public static Collection<Object[]> setup() { | 
|  | DelayedDebugTestConfig cf = | 
|  | temp -> new CfDebugTestConfig().addPaths(DebugTestBase.DEBUGGEE_JAR); | 
|  | DelayedDebugTestConfig r8cf = temp -> new R8CfDebugTestResourcesConfig(temp); | 
|  | DelayedDebugTestConfig d8 = temp -> new D8DebugTestResourcesConfig(temp); | 
|  | return ImmutableList.of( | 
|  | new Object[] {"CF", cf}, | 
|  | new Object[] {"D8", d8}, | 
|  | new Object[] {"R8/CF", r8cf}); | 
|  | } | 
|  |  | 
|  | public SynchronizedBlockTest(String name, DelayedDebugTestConfig config) { | 
|  | this.name = name; | 
|  | this.config = config.getConfig(temp); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testEmptyBlock() throws Throwable { | 
|  | final String method = "emptyBlock"; | 
|  | runDebugTest( | 
|  | config, | 
|  | CLASS, | 
|  | breakpoint(CLASS, method), | 
|  | run(), | 
|  | checkLine(FILE, 8), | 
|  | checkLocal("obj"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 9), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 10), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 11), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | checkLocal("y"), | 
|  | run()); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testNonThrowingBlock() throws Throwable { | 
|  | final String method = "nonThrowingBlock"; | 
|  | runDebugTest( | 
|  | config, | 
|  | CLASS, | 
|  | breakpoint(CLASS, method), | 
|  | run(), | 
|  | checkLine(FILE, 15), | 
|  | checkLocal("obj"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 16), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 17), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 18), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 19), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 20), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | checkLocal("y"), | 
|  | run()); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testThrowingBlock() throws Throwable { | 
|  | Assume.assumeThat( | 
|  | "Connection timeout on 6.0.1 runtime. b/67671771", | 
|  | ToolHelper.getDexVm().getVersion(), not(DexVm.ART_6_0_1_TARGET.getVersion())); | 
|  | final String method = "throwingBlock"; | 
|  | runDebugTest( | 
|  | config, | 
|  | CLASS, | 
|  | breakpoint(CLASS, method), | 
|  | run(), | 
|  | checkLine(FILE, 25), | 
|  | checkLocal("obj"), | 
|  | checkNoLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 26), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | checkNoLocal("y"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 27), | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | checkNoLocal("y"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 28), // synchronized block end | 
|  | checkLocal("obj"), | 
|  | checkLocal("x"), | 
|  | checkNoLocal("y"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 31), // catch handler | 
|  | checkLocal("obj"), | 
|  | checkNoLocal("x"), | 
|  | checkNoLocal("y"), | 
|  | stepOver(), | 
|  | run()); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testNestedNonThrowingBlock() throws Throwable { | 
|  | final String method = "nestedNonThrowingBlock"; | 
|  | runDebugTest( | 
|  | config, | 
|  | CLASS, | 
|  | breakpoint(CLASS, method), | 
|  | run(), | 
|  | checkLine(FILE, 35), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 36), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 37), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 38), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 39), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 40), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 41), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 42), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 43), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | checkLocal("y"), | 
|  | run()); | 
|  | } | 
|  |  | 
|  | @Test | 
|  | public void testNestedThrowingBlock() throws Throwable { | 
|  | final String method = "nestedThrowingBlock"; | 
|  | runDebugTest( | 
|  | config, | 
|  | CLASS, | 
|  | breakpoint(CLASS, method), | 
|  | run(), | 
|  | checkLine(FILE, 48), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 49), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 50), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 51), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 52), | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 53), // inner synchronize block end | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 54), // outer synchronize block end | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkLocal("x"), | 
|  | stepOver(), | 
|  | checkLine(FILE, 57), // catch handler | 
|  | checkLocal("obj1"), | 
|  | checkLocal("obj2"), | 
|  | checkNoLocal("x"), | 
|  | run()); | 
|  | } | 
|  | } |