| // 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.ir.optimize.boxedprimitives; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertTrue; |
| |
| 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.DexItemFactory; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.utils.StringUtils; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.google.common.collect.Sets; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Set; |
| import org.junit.Test; |
| 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 ReverseBoxingOperationsTest extends TestBase { |
| |
| @Parameter(0) |
| public TestParameters parameters; |
| |
| @Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withAllRuntimesAndApiLevels().build(); |
| } |
| |
| @Test |
| public void testUnboxingRemoved() throws Exception { |
| testForR8(parameters.getBackend()) |
| .addInnerClasses(getClass()) |
| .addKeepMainRule(Main.class) |
| .enableInliningAnnotations() |
| .setMinApi(parameters) |
| .compile() |
| .inspect(this::assertBoxOperationsRemoved) |
| .run(parameters.getRuntime(), Main.class) |
| .assertSuccessWithOutput(getExpectedResult()); |
| } |
| |
| private void assertBoxOperationsRemoved(CodeInspector codeInspector) { |
| DexItemFactory factory = codeInspector.getFactory(); |
| |
| Set<DexMethod> unboxMethods = Sets.newIdentityHashSet(); |
| Set<DexMethod> boxMethods = Sets.newIdentityHashSet(); |
| for (DexType primitiveType : factory.unboxPrimitiveMethod.keySet()) { |
| unboxMethods.add(factory.getUnboxPrimitiveMethod(primitiveType)); |
| boxMethods.add(factory.getBoxPrimitiveMethod(primitiveType)); |
| } |
| |
| // All box operations should have been removed, except for the unbox methods that act as null |
| // checks, which may or may not be replaced by null-checks depending if they are reprocessed. |
| assertEquals( |
| 24, |
| codeInspector |
| .clazz(Main.class) |
| .allMethods(m -> !m.getOriginalMethodName().equals("main")) |
| .size()); |
| codeInspector |
| .clazz(Main.class) |
| .allMethods(m -> !m.getOriginalMethodName().equals("main")) |
| .forEach( |
| m -> |
| assertTrue( |
| m.streamInstructions() |
| .noneMatch(i -> i.isInvoke() && boxMethods.contains(i.getMethod())))); |
| codeInspector |
| .clazz(Main.class) |
| .allMethods( |
| m -> |
| !m.getOriginalMethodName().equals("main") |
| && (m.getOriginalMethodName().contains("Unbox") |
| || m.getOriginalMethodName().contains("NonNull"))) |
| .forEach( |
| m -> |
| assertTrue( |
| m.streamInstructions() |
| .noneMatch(i -> i.isInvoke() && unboxMethods.contains(i.getMethod())))); |
| } |
| |
| private String getExpectedResult() { |
| String[] resultItems = {"1", "1", "1.0", "1.0", "1", "1", "c", "true"}; |
| String[] resultItems2 = {"2", "2", "2.0", "2.0", "2", "2", "e", "false"}; |
| List<String> result = new ArrayList<>(); |
| for (int i = 0; i < resultItems.length; i++) { |
| String item = resultItems[i]; |
| String item2 = resultItems2[i]; |
| result.add(">" + item); |
| result.add(">" + item); |
| result.add(">npe failure"); |
| result.add(">" + item); |
| result.add(">" + item2); |
| } |
| return StringUtils.lines(result); |
| } |
| |
| public static class Main { |
| |
| public static void main(String[] args) { |
| int i = System.currentTimeMillis() > 0 ? 1 : 0; |
| System.out.println(intUnboxTest(i)); |
| System.out.println(intTest(i)); |
| try { |
| System.out.println(intTest(null)); |
| } catch (NullPointerException npe7) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(intTestNonNull(i)); |
| System.out.println(intTestNonNull(i + 1)); |
| |
| long l = System.currentTimeMillis() > 0 ? 1L : 0L; |
| System.out.println(longUnboxTest(l)); |
| System.out.println(longTest(l)); |
| try { |
| System.out.println(longTest(null)); |
| } catch (NullPointerException npe6) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(longTestNonNull(l)); |
| System.out.println(longTestNonNull(l + 1)); |
| |
| double d = System.currentTimeMillis() > 0 ? 1.0 : 0.0; |
| System.out.println(doubleUnboxTest(d)); |
| System.out.println(doubleTest(d)); |
| try { |
| System.out.println(doubleTest(null)); |
| } catch (NullPointerException npe5) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(doubleTestNonNull(d)); |
| System.out.println(doubleTestNonNull(d + 1)); |
| |
| float f = System.currentTimeMillis() > 0 ? 1.0f : 0.0f; |
| System.out.println(floatUnboxTest(f)); |
| System.out.println(floatTest(f)); |
| try { |
| System.out.println(floatTest(null)); |
| } catch (NullPointerException npe4) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(floatTestNonNull(f)); |
| System.out.println(floatTestNonNull(f + 1)); |
| |
| byte b = (byte) (System.currentTimeMillis() > 0 ? 1 : 0); |
| System.out.println(byteUnboxTest(b)); |
| System.out.println(byteTest(b)); |
| try { |
| System.out.println(byteTest(null)); |
| } catch (NullPointerException npe3) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(byteTestNonNull(b)); |
| System.out.println(byteTestNonNull((byte) (b + 1))); |
| |
| short s = (short) (System.currentTimeMillis() > 0 ? 1 : 0); |
| System.out.println(shortUnboxTest(s)); |
| System.out.println(shortTest(s)); |
| try { |
| System.out.println(shortTest(null)); |
| } catch (NullPointerException npe2) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(shortTestNonNull(s)); |
| System.out.println(shortTestNonNull((short) (s + 1))); |
| |
| char c = System.currentTimeMillis() > 0 ? 'c' : 'd'; |
| System.out.println(charUnboxTest(c)); |
| System.out.println(charTest(c)); |
| try { |
| System.out.println(charTest(null)); |
| } catch (NullPointerException npe1) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(charTestNonNull(c)); |
| System.out.println(charTestNonNull('e')); |
| |
| boolean bool = System.currentTimeMillis() > 0; |
| System.out.println(booleanUnboxTest(bool)); |
| System.out.println(booleanTest(bool)); |
| try { |
| System.out.println(booleanTest(null)); |
| } catch (NullPointerException npe) { |
| System.out.println("npe failure"); |
| } |
| System.out.println(booleanTestNonNull(bool)); |
| System.out.println(booleanTestNonNull(false)); |
| } |
| |
| @NeverInline |
| public static int intUnboxTest(int i) { |
| System.out.print(">"); |
| return Integer.valueOf(i).intValue(); |
| } |
| |
| @NeverInline |
| public static Integer intTest(Integer i) { |
| System.out.print(">"); |
| return Integer.valueOf(i.intValue()); |
| } |
| |
| @NeverInline |
| public static Integer intTestNonNull(Integer i) { |
| System.out.print(">"); |
| return Integer.valueOf(i.intValue()); |
| } |
| |
| @NeverInline |
| public static double doubleUnboxTest(double d) { |
| System.out.print(">"); |
| return Double.valueOf(d).doubleValue(); |
| } |
| |
| @NeverInline |
| public static Double doubleTest(Double d) { |
| System.out.print(">"); |
| return Double.valueOf(d.doubleValue()); |
| } |
| |
| @NeverInline |
| public static Double doubleTestNonNull(Double d) { |
| System.out.print(">"); |
| return Double.valueOf(d.doubleValue()); |
| } |
| |
| @NeverInline |
| public static long longUnboxTest(long l) { |
| System.out.print(">"); |
| return Long.valueOf(l).longValue(); |
| } |
| |
| @NeverInline |
| public static Long longTest(Long l) { |
| System.out.print(">"); |
| return Long.valueOf(l.longValue()); |
| } |
| |
| @NeverInline |
| public static Long longTestNonNull(Long l) { |
| System.out.print(">"); |
| return Long.valueOf(l.longValue()); |
| } |
| |
| @NeverInline |
| public static float floatUnboxTest(float f) { |
| System.out.print(">"); |
| return Float.valueOf(f).floatValue(); |
| } |
| |
| @NeverInline |
| public static Float floatTest(Float f) { |
| System.out.print(">"); |
| return Float.valueOf(f.floatValue()); |
| } |
| |
| @NeverInline |
| public static Float floatTestNonNull(Float f) { |
| System.out.print(">"); |
| return Float.valueOf(f.floatValue()); |
| } |
| |
| @NeverInline |
| public static short shortUnboxTest(short s) { |
| System.out.print(">"); |
| return Short.valueOf(s).shortValue(); |
| } |
| |
| @NeverInline |
| public static Short shortTest(Short s) { |
| System.out.print(">"); |
| return Short.valueOf(s.shortValue()); |
| } |
| |
| @NeverInline |
| public static Short shortTestNonNull(Short s) { |
| System.out.print(">"); |
| return Short.valueOf(s.shortValue()); |
| } |
| |
| @NeverInline |
| public static char charUnboxTest(char c) { |
| System.out.print(">"); |
| return Character.valueOf(c).charValue(); |
| } |
| |
| @NeverInline |
| public static Character charTest(Character c) { |
| System.out.print(">"); |
| return Character.valueOf(c.charValue()); |
| } |
| |
| @NeverInline |
| public static Character charTestNonNull(Character c) { |
| System.out.print(">"); |
| return Character.valueOf(c.charValue()); |
| } |
| |
| @NeverInline |
| public static byte byteUnboxTest(byte b) { |
| System.out.print(">"); |
| return Byte.valueOf(b).byteValue(); |
| } |
| |
| @NeverInline |
| public static Byte byteTest(Byte b) { |
| System.out.print(">"); |
| return Byte.valueOf(b.byteValue()); |
| } |
| |
| @NeverInline |
| public static Byte byteTestNonNull(Byte b) { |
| System.out.print(">"); |
| return Byte.valueOf(b.byteValue()); |
| } |
| |
| @NeverInline |
| public static boolean booleanUnboxTest(boolean b) { |
| System.out.print(">"); |
| return Boolean.valueOf(b).booleanValue(); |
| } |
| |
| @NeverInline |
| public static Boolean booleanTest(Boolean b) { |
| System.out.print(">"); |
| return Boolean.valueOf(b.booleanValue()); |
| } |
| |
| @NeverInline |
| public static Boolean booleanTestNonNull(Boolean b) { |
| System.out.print(">"); |
| return Boolean.valueOf(b.booleanValue()); |
| } |
| } |
| } |