blob: 7ffe710049cbec7f21c39b9171ee098e816b0acf [file] [log] [blame]
// Copyright (c) 2023, 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.classinit;
import com.android.tools.r8.AlwaysInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.Position;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class InitClassPopCfTest extends TestBase {
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withCfRuntimes().build();
}
private final TestParameters parameters;
public InitClassPopCfTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testInitClass() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.enableInliningAnnotations()
.enableAlwaysInliningAnnotations()
.addOptionsModification(
internalOptions -> internalOptions.testing.irModifier = this::modifyIR)
.addKeepRules("-keepattributes LineNumberTable")
.addKeepRules("-keep class * { static java.lang.Object f; }")
.addKeepMainRule(Main.class)
.compile()
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("0", "clinit A", "5504", "5");
}
private void modifyIR(IRCode irCode, AppView<?> appView) {
InstructionIterator instructionIterator = irCode.instructionIterator();
Position pos = null;
while (instructionIterator.hasNext()) {
Instruction next = instructionIterator.next();
// Modify the position so code can be shared except for initClass and invoke-static that
// will be transformed into initClass.
if (!next.isInitClass()
&& !(next.isInvokeStatic()
&& next.asInvokeStatic().getInvokedMethod().getName().toString().equals("nop"))) {
if (pos == null) {
pos = next.getPosition();
}
next.forceOverwritePosition(pos);
}
}
}
public static class A {
static {
System.out.println("clinit A");
}
static Object f;
@AlwaysInline
static void nop() {}
}
public static class Main {
public static void main(String[] args) {
int i = System.currentTimeMillis() > 0 ? 5 : 3;
if (System.currentTimeMillis() > 0) {
System.out.println("0");
A.nop();
print((((i << 2) + 1 << 3) + 4) << 5);
} else if (System.currentTimeMillis() > 1) {
System.out.println("1");
A.nop();
print((((i << 2) + 1 << 3) + 4) << 5);
} else if (System.currentTimeMillis() > 2) {
System.out.println("2");
A.nop();
print((((i << 2) + 1 << 3) + 4) << 5);
} else {
System.out.println("3");
A.nop();
print((((i << 2) + 1 << 3) + 4) << 5);
}
System.out.println(i);
}
@NeverInline
private static void print(int k) {
System.out.println(k);
}
}
}