blob: 8beaf1487fc0fff725819e74afe8a26dedcf7578 [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 org.junit.Assert.assertTrue;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.jasmin.JasminTestBase;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import org.junit.Assert;
import org.junit.Test;
// Test documenting null-value usages with the reference implementation.
public class NullArrayAndNullObjectValueTest extends JasminTestBase {
@Test
public void testNullIsArray() throws Exception {
JasminBuilder jasminBuilder = new JasminBuilder();
ClassBuilder classBuilder = jasminBuilder.addClass("TestClass");
// Store directly to the null value.
classBuilder.addStaticMethod(
"nullArrayStore",
ImmutableList.of(),
"V",
".limit stack 10",
".limit locals 10",
".catch java/lang/NullPointerException from L0 to L1 using L2",
"aconst_null",
"iconst_0",
"iconst_1",
"L0:",
"iastore",
"L1:",
"return",
"L2:",
"pop",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"ldc \"NPE\"",
"invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
"return");
// Load directly from the null value.
classBuilder.addStaticMethod(
"nullArrayLoad",
ImmutableList.of(),
"V",
".limit stack 10",
".limit locals 10",
".catch java/lang/NullPointerException from L0 to L1 using L2",
"aconst_null",
"iconst_0",
"L0:",
"iaload",
"L1:",
"pop",
"return",
"L2:",
"pop",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"ldc \"NPE\"",
"invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
"return");
// Get the length of the null value.
classBuilder.addStaticMethod(
"nullArrayLength",
ImmutableList.of(),
"V",
".limit stack 10",
".limit locals 10",
".catch java/lang/NullPointerException from L0 to L1 using L2",
"aconst_null",
"L0:",
"arraylength",
"L1:",
"pop",
"return",
"L2:",
"pop",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"ldc \"NPE\"",
"invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
"return");
// Use the same null value (local containing null) as both an object type and an array type.
classBuilder.addStaticMethod(
"nullToObjectAndArray",
ImmutableList.of(),
"V",
".limit stack 10",
".limit locals 10",
// Stored null in local 0
"aconst_null",
"astore 0",
// Create single-cell array of object type and store the null in it.
"iconst_1",
"anewarray java/lang/String",
"iconst_0",
"aload 0",
"aastore",
// Create single-cell array of array type and store the null in it.
"iconst_1",
"anewarray [I",
"iconst_0",
"aload 0",
"aastore",
"return");
classBuilder.addMainMethod(
".limit stack 5",
".limit locals 5",
"invokestatic TestClass/nullToObjectAndArray()V",
"invokestatic TestClass/nullArrayStore()V",
"invokestatic TestClass/nullArrayLoad()V",
"invokestatic TestClass/nullArrayLength()V",
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 0, riResult.exitCode);
Path d8Jar = temp.getRoot().toPath().resolve("d8-out.jar");
D8.run(
D8Command.builder().addProgramFiles(riJar).setOutput(d8Jar, OutputMode.DexIndexed).build());
ProcessResult d8Result = ToolHelper.runArtRaw(d8Jar.toString(), "TestClass");
Assert.assertEquals(d8Result.toString(), 0, riResult.exitCode);
Assert.assertEquals(riResult.stdout, d8Result.stdout);
}
@Test
public void testObjectNotArray() throws Exception {
JasminBuilder jasminBuilder = new JasminBuilder();
ClassBuilder classBuilder = jasminBuilder.addClass("TestClass");
// Invalid attempt at using object as an array.
classBuilder.addStaticMethod(
"objectAsArray",
ImmutableList.of("Ljava/lang/Object;"),
"V",
".limit stack 10",
".limit locals 10",
".catch java/lang/NullPointerException from L0 to L1 using L2",
"aload 0",
"iconst_0",
"iconst_1",
"L0:",
"iastore",
"L1:",
"return",
"L2:",
"pop",
"getstatic java/lang/System/out Ljava/io/PrintStream;",
"ldc \"NPE\"",
"invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V",
"return");
classBuilder.addMainMethod(
".limit stack 5",
".limit locals 5",
"aconst_null",
"invokestatic TestClass/objectAsArray(Ljava/lang/Object;)V",
"return");
Path riJar = temp.getRoot().toPath().resolve("ri-out.jar");
jasminBuilder.writeJar(riJar, new DiagnosticsHandler() {});
ProcessResult riResult = ToolHelper.runJava(riJar, "TestClass");
Assert.assertEquals(riResult.toString(), 1, riResult.exitCode);
assertTrue(riResult.stderr.contains("VerifyError"));
// This test does not check that D8 compiles or fails in any particular way as the input is
// invalid. The old frontend used to hit an assertion, the new frontend does not.
}
}