| // 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.regress.b113326860; |
| |
| import static com.android.tools.r8.utils.DexInspectorMatchers.isPresent; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.CompilationFailedException; |
| import com.android.tools.r8.CompilationMode; |
| import com.android.tools.r8.D8Command; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.code.Sput; |
| import com.android.tools.r8.code.SputBoolean; |
| import com.android.tools.r8.code.SputObject; |
| import com.android.tools.r8.ir.code.SingleConstant; |
| import com.android.tools.r8.origin.Origin; |
| import com.android.tools.r8.utils.AndroidApp; |
| import com.android.tools.r8.utils.DexInspector; |
| import com.android.tools.r8.utils.DexInspector.ClassSubject; |
| import com.android.tools.r8.utils.DexInspector.MethodSubject; |
| import com.google.common.collect.ImmutableList; |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.concurrent.ExecutionException; |
| import org.junit.Test; |
| |
| class TestClassDoOptimize { |
| private static boolean b = false; |
| private static int i = 3; |
| private static Class clazz; |
| static { |
| clazz = TestClassDoOptimize.class; |
| b = true; |
| i = 42; |
| } |
| } |
| |
| class TestClassDoNotOptimize { |
| |
| private static boolean initialized = false; |
| private static final TestClassDoNotOptimize INSTANCE; |
| |
| TestClassDoNotOptimize() { |
| if (!initialized) { |
| System.out.println("Not initialized as expected"); |
| } |
| } |
| |
| static { |
| INSTANCE = new TestClassDoNotOptimize(); |
| initialized = true; |
| } |
| } |
| |
| class TestClassDoNotOptimize2 { |
| static boolean b = false; |
| static { |
| boolean forcingOtherClassInit = TestClassDoNotOptimize3.b; |
| b = true; |
| } |
| |
| static void m() { |
| System.out.println(b); |
| } |
| } |
| |
| class TestClassDoNotOptimize3 { |
| static boolean b = false; |
| static { |
| TestClassDoNotOptimize2.m(); |
| } |
| } |
| |
| class TestDoWhileLoop { |
| static int i = 0; |
| static int j = 0; |
| static { |
| do { |
| i = 42; |
| System.out.println(i); |
| j = j + 1; |
| i = 10; |
| } while (j < 10); |
| } |
| |
| public static void main(String[] args) { |
| System.out.println(TestDoWhileLoop.i); |
| } |
| } |
| |
| public class B113326860 { |
| |
| private DexInspector compileTestClasses(List<Class> classes) |
| throws IOException, CompilationFailedException, ExecutionException { |
| D8Command.Builder builder = D8Command.builder().setMode(CompilationMode.RELEASE); |
| for (Class c : classes) { |
| builder.addClassProgramData(ToolHelper.getClassAsBytes(c), Origin.unknown()); |
| } |
| AndroidApp app = ToolHelper.runD8(builder); |
| return new DexInspector(app); |
| } |
| |
| @Test |
| public void optimizedClassInitializer() |
| throws IOException, CompilationFailedException, ExecutionException { |
| DexInspector inspector = compileTestClasses(ImmutableList.of(TestClassDoOptimize.class)); |
| ClassSubject clazz = inspector.clazz(TestClassDoOptimize.class); |
| assertThat(clazz, isPresent()); |
| MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of()); |
| assertThat(method, isPresent()); |
| assertFalse(Arrays.stream(method.getMethod().getCode().asDexCode().instructions) |
| .anyMatch(i -> i instanceof SputBoolean || i instanceof Sput)); |
| assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions) |
| .anyMatch(i -> i instanceof SputObject)); |
| } |
| |
| @Test |
| public void nonOptimizedClassInitializer() |
| throws ExecutionException, CompilationFailedException, IOException { |
| DexInspector inspector = |
| compileTestClasses(ImmutableList.of(TestClassDoNotOptimize.class)); |
| ClassSubject clazz = inspector.clazz(TestClassDoNotOptimize.class); |
| assertThat(clazz, isPresent()); |
| MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of()); |
| assertThat(method, isPresent()); |
| assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions) |
| .anyMatch(i -> i instanceof SputBoolean)); |
| } |
| |
| @Test |
| public void nonOptimizedClassInitializer2() |
| throws ExecutionException, CompilationFailedException, IOException { |
| DexInspector inspector = compileTestClasses( |
| ImmutableList.of(TestClassDoNotOptimize2.class, TestClassDoNotOptimize3.class)); |
| ClassSubject clazz = inspector.clazz(TestClassDoNotOptimize2.class); |
| assertThat(clazz, isPresent()); |
| MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of()); |
| assertThat(method, isPresent()); |
| assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions) |
| .anyMatch(i -> i instanceof SputBoolean)); |
| } |
| |
| @Test |
| public void doWhileLoop() throws ExecutionException, CompilationFailedException, IOException { |
| DexInspector inspector = compileTestClasses(ImmutableList.of(TestDoWhileLoop.class)); |
| ClassSubject clazz = inspector.clazz(TestDoWhileLoop.class); |
| assertThat(clazz, isPresent()); |
| MethodSubject method = clazz.method("void", "<clinit>", ImmutableList.of()); |
| assertThat(method, isPresent()); |
| // Leave the const 42 and the assignment in there! |
| assertTrue(Arrays.stream(method.getMethod().getCode().asDexCode().instructions) |
| .anyMatch(i -> i instanceof SingleConstant && (((SingleConstant) i).decodedValue() == 42))); |
| } |
| } |