blob: 380127bc94ff99986b6ed72b46e26184b0c4b1b2 [file] [log] [blame]
// Copyright (c) 2021, 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.desugar;
import static com.android.tools.r8.TestRuntime.CfVm.JDK11;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.transformers.ClassFileTransformer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.objectweb.asm.Opcodes;
// Test for reproducing b/192310793.
@RunWith(Parameterized.class)
public class ConcurrencyTest extends TestBase {
@Parameter() public TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters()
.withCfRuntimesEndingAtExcluding(JDK11)
.withDexRuntimes()
.withApiLevel(AndroidApiLevel.B)
.build());
}
public Collection<Class<?>> getClasses() {
return ImmutableList.of(Main.class);
}
public Collection<byte[]> getTransformedClasses() throws Exception {
ClassFileTransformer transformer =
withNest(Host.class)
.setVersion(CfVersion.V1_8)
.transformMethodInsnInMethod(
"callPrivate",
((opcode, owner, name, descriptor, isInterface, continuation) -> {
continuation.visitMethodInsn(
name.equals("hello") ? Opcodes.INVOKEVIRTUAL : opcode,
owner,
name,
descriptor,
isInterface);
}));
for (String s : new String[] {"a", "b", "c", "d", "e"}) {
for (int i = 0; i < 10; i++) {
transformer.setPrivate(Host.class.getDeclaredMethod(s + "0" + i));
}
}
return ImmutableList.of(
transformer.transform(),
withNest(A.class).transform(),
withNest(B.class).transform(),
withNest(C.class).transform(),
withNest(D.class).transform(),
withNest(E.class).transform());
}
private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
return transformer(clazz).setNest(Host.class, A.class, B.class, C.class, D.class, E.class);
}
@Test
public void testD8() throws Exception {
try {
testForD8(parameters.getBackend())
.addProgramClasses(getClasses())
.addProgramClassFileData(getTransformedClasses())
.compile();
} catch (CompilationFailedException e) {
if (e.getCause() instanceof ArrayIndexOutOfBoundsException) {
// TODO(b/192310793): This should not happen.
return;
}
throw e;
}
}
@Test
public void testR8() throws Exception {
assumeTrue(parameters.getBackend().isDex());
try {
testForR8(parameters.getBackend())
.addProgramClasses(getClasses())
.addProgramClassFileData(getTransformedClasses())
.setMinApi(parameters.getApiLevel())
.addKeepAllClassesRule()
.compile();
} catch (CompilationFailedException e) {
if (e.getCause() instanceof AssertionError
&& e.getCause()
.getStackTrace()[0]
.getClassName()
.equals(
"com.android.tools.r8.ir.desugar.NonEmptyCfInstructionDesugaringCollection")) {
// TODO(b/192446461): This should not happen.
return;
}
throw e;
}
}
static class Host {
/* will be private */ void a00() {}
/* will be private */ void a01() {}
/* will be private */ void a02() {}
/* will be private */ void a03() {}
/* will be private */ void a04() {}
/* will be private */ void a05() {}
/* will be private */ void a06() {}
/* will be private */ void a07() {}
/* will be private */ void a08() {}
/* will be private */ void a09() {}
/* will be private */ void b00() {}
/* will be private */ void b01() {}
/* will be private */ void b02() {}
/* will be private */ void b03() {}
/* will be private */ void b04() {}
/* will be private */ void b05() {}
/* will be private */ void b06() {}
/* will be private */ void b07() {}
/* will be private */ void b08() {}
/* will be private */ void b09() {}
/* will be private */ void c00() {}
/* will be private */ void c01() {}
/* will be private */ void c02() {}
/* will be private */ void c03() {}
/* will be private */ void c04() {}
/* will be private */ void c05() {}
/* will be private */ void c06() {}
/* will be private */ void c07() {}
/* will be private */ void c08() {}
/* will be private */ void c09() {}
/* will be private */ void d00() {}
/* will be private */ void d01() {}
/* will be private */ void d02() {}
/* will be private */ void d03() {}
/* will be private */ void d04() {}
/* will be private */ void d05() {}
/* will be private */ void d06() {}
/* will be private */ void d07() {}
/* will be private */ void d08() {}
/* will be private */ void d09() {}
/* will be private */ void e00() {}
/* will be private */ void e01() {}
/* will be private */ void e02() {}
/* will be private */ void e03() {}
/* will be private */ void e04() {}
/* will be private */ void e05() {}
/* will be private */ void e06() {}
/* will be private */ void e07() {}
/* will be private */ void e08() {}
/* will be private */ void e09() {}
private void hello() {}
public static void callPrivate() {
// The private method "hello" is called with invokevirtual.
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
new Host().hello();
}
}
static class A {
public void foo() {
// Will be virtual invoke to private methods.
new Host().a00();
new Host().a01();
new Host().a02();
new Host().a03();
new Host().a04();
new Host().a05();
new Host().a06();
new Host().a07();
new Host().a08();
new Host().a09();
}
}
static class B {
public void foo() {
// Will be virtual invoke to private methods.
new Host().b00();
new Host().b01();
new Host().b02();
new Host().b03();
new Host().b04();
new Host().b05();
new Host().b06();
new Host().b07();
new Host().b08();
new Host().b09();
}
}
static class C {
public void foo() {
// Will be virtual invoke to private methods.
new Host().c00();
new Host().c01();
new Host().c02();
new Host().c03();
new Host().c04();
new Host().c05();
new Host().c06();
new Host().c07();
new Host().c08();
new Host().c09();
}
}
static class D {
public void foo() {
// Will be virtual invoke to private methods.
new Host().d00();
new Host().d01();
new Host().d02();
new Host().d03();
new Host().d04();
new Host().d05();
new Host().d06();
new Host().d07();
new Host().d08();
new Host().d09();
}
}
static class E {
public void foo() {
// Will be virtual invoke to private methods.
new Host().e00();
new Host().e01();
new Host().e02();
new Host().e03();
new Host().e04();
new Host().e05();
new Host().e06();
new Host().e07();
new Host().e08();
new Host().e09();
}
}
static class Main {
public static void main(String[] args) {
new A().foo();
new B().foo();
new C().foo();
new D().foo();
new E().foo();
Host.callPrivate();
}
}
}