blob: 9436d07054705d98d66c9209db18853f561fa7a4 [file] [log] [blame]
// 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.debug;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
import org.junit.Test;
/**
* Regression test to ensure that an incomplete phi creation cannot introduce a local before the
* locals actual start. The recursive read-register in IRBuilder did not previously account for the
* change in blocks when determining the local information of the incomplete phi.
*/
public class NoLocalForPhiDebugTest extends DebugTestBase {
private static final String className = "NoLocalForPhi";
private static final String sourcefile = className + ".j";
private static final String methodName = "test";
@Test
public void testCf() throws Throwable {
JasminBuilder builder = getBuilderForUselessCheckcast(className, methodName);
Path outdir = temp.newFolder().toPath();
builder.writeClassFiles(outdir);
CfDebugTestConfig config = new CfDebugTestConfig();
config.addPaths(outdir);
run(config);
}
@Test
public void testD8() throws Throwable {
JasminBuilder builder = getBuilderForUselessCheckcast(className, methodName);
List<Path> outputs = builder.writeClassFiles(temp.newFolder().toPath());
run(new D8DebugTestConfig().compileAndAdd(temp, outputs));
}
private void run(DebugTestConfig config) throws Throwable {
runDebugTest(
config,
className,
breakpoint(className, methodName),
run(),
checkLine(sourcefile, 1),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 2),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 3),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 4),
checkLocal("arg"),
checkLocal("local"),
// local == 0 => branch to line 5
stepOver(),
checkLine(sourcefile, 5),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 2),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 3),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 4),
checkLocal("arg"),
checkLocal("local"),
// local == -1 => branch to line 6 then 7
stepOver(),
checkLine(sourcefile, 6),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 7),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 2),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 3),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 4),
checkLocal("arg"),
checkLocal("local"),
// local == 1 => branch to line 6 then 8
stepOver(),
checkLine(sourcefile, 6),
checkLocal("arg"),
checkNoLocal("local"),
stepOver(),
checkLine(sourcefile, 8),
checkLocal("arg"),
checkNoLocal("local"),
run());
}
private JasminBuilder getBuilderForUselessCheckcast(String testClassName, String testMethodName) {
JasminBuilder builder = new JasminBuilder();
JasminBuilder.ClassBuilder clazz = builder.addClass(testClassName);
clazz.addStaticMethod(testMethodName, ImmutableList.of("Ljava/lang/Object;"), "V",
".limit stack 2",
".limit locals 2",
".var 0 is arg Ljava/lang/Object; from L_init to L_end",
".var 1 is local I from L_local_start to L_local_end",
"L_init:",
".line 1",
" ldc 0",
" istore 1",
"L_join:", // A phi flowing to 'local' starts here.
".line 2",
" getstatic java/lang/System/out Ljava/io/PrintStream;",
".line 3", // An intermediate instruction to ensure the phi did not start the local.
" nop",
"L_local_start:", // Delayed start of local.
".line 4",
" iload 1",
" invokevirtual java/io/PrintStream/println(I)V",
" iload 1",
" ifne L_b2",
"L_local_end:", // End of local (could also just end at exit).
"L_b1:",
".line 5",
" ldc -1",
" istore 1",
" goto L_join", // Back branch to ensure an incomplete phi is created in L_join.
"L_b2:",
".line 6",
" iload 1",
" ifgt L_b3",
".line 7",
" ldc 1",
" istore 1",
" goto L_join", // Back branch to ensure an incomplete phi is created in L_join.
"L_b3:",
".line 8",
"return",
"L_end:");
clazz.addMainMethod(
".limit stack 2",
".limit locals 1",
"aconst_null",
"invokestatic " + testClassName + "/" + testMethodName + "(Ljava/lang/Object;)V",
"return");
return builder;
}
}