blob: 0031854acba27d928dc819264e0b2f258d635c6f [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.ir.optimize;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.jasmin.JasminTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.UnverifiableCfCodeDiagnostic;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class B116282409 extends JasminTestBase {
private static List<byte[]> programClassFileData;
@Parameter(0)
public TestParameters parameters;
@Parameter(1)
public boolean enableVerticalClassMerging;
@Rule public ExpectedException exception = ExpectedException.none();
@Parameters(name = "{0}, vertical class merging: {1}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
}
@BeforeClass
public static void setup() throws Exception {
JasminBuilder jasminBuilder = new JasminBuilder();
// Create a class A with a default constructor that prints "In A.<init>()".
ClassBuilder classBuilder = jasminBuilder.addClass("A");
classBuilder.addMethod(
"public",
"<init>",
ImmutableList.of(),
"V",
".limit stack 2",
".limit locals 1",
"aload_0",
"invokespecial java/lang/Object/<init>()V",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"ldc \"In A.<init>()\"",
"invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
"return");
// Create a class B that inherits from A.
classBuilder = jasminBuilder.addClass("B", "A");
// Also add a simple method that the class inliner would inline.
classBuilder.addVirtualMethod(
"m", "I", ".limit stack 5", ".limit locals 5", "bipush 42", "ireturn");
// Add a test class that initializes an instance of B using A.<init>.
classBuilder = jasminBuilder.addClass("TestClass");
classBuilder.addMainMethod(
".limit stack 5",
".limit locals 5",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"new B",
"dup",
"invokespecial A/<init>()V", // NOTE: usually B.<init>
"invokevirtual B/m()I",
"invokevirtual java/io/PrintStream/println(I)V",
"return");
programClassFileData = jasminBuilder.buildClasses();
}
@Test
public void testJvm() throws Exception {
parameters.assumeJvmTestParameters();
testForJvm(parameters)
.addProgramClassFileData(programClassFileData)
.run(parameters.getRuntime(), "TestClass")
.assertFailureWithErrorThatThrows(VerifyError.class)
.assertFailureWithErrorThatMatches(containsString("Call to wrong initialization method"));
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClassFileData(programClassFileData)
.addKeepMainRule("TestClass")
.addOptionsModification(
options ->
options.getVerticalClassMergerOptions().setEnabled(enableVerticalClassMerging))
.allowDiagnosticWarningMessages()
.setMinApi(parameters)
.compileWithExpectedDiagnostics(
diagnostics ->
diagnostics.assertWarningsMatch(
allOf(
diagnosticType(UnverifiableCfCodeDiagnostic.class),
diagnosticMessage(
containsString(
"Constructor mismatch, expected constructor from B, but was"
+ " A.<init>()")))))
.run(parameters.getRuntime(), "TestClass")
.applyIf(
(parameters.isCfRuntime() || parameters.getDexRuntimeVersion().isDalvik())
&& !enableVerticalClassMerging,
runResult ->
runResult
.assertFailureWithErrorThatThrows(VerifyError.class)
.assertFailureWithErrorThatMatches(
containsString(
parameters.isCfRuntime()
? "Call to wrong initialization method"
: "VFY: invoke-direct <init> on super only allowed for 'this' in"
+ " <init>")),
runResult -> runResult.assertSuccessWithOutputLines("In A.<init>()", "42"));
}
}