/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ public class Main { /// CHECK-START: Main Main.keepTest(Main) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK: InvokeStaticOrDirect /// CHECK-START: Main Main.keepTest(Main) instruction_simplifier (after) /// CHECK: NullCheck /// CHECK: InvokeStaticOrDirect public Main keepTest(Main m) { return m.g(); } /// CHECK-START: Main Main.thisTest() builder (after) /// CHECK-NOT: NullCheck /// CHECK: InvokeStaticOrDirect public Main thisTest() { return g(); } /// CHECK-START: Main Main.newInstanceRemoveTest() builder (after) /// CHECK: NewInstance /// CHECK: InvokeStaticOrDirect /// CHECK: InvokeStaticOrDirect /// CHECK-START: Main Main.newInstanceRemoveTest() builder (after) /// CHECK-NOT: NullCheck public Main newInstanceRemoveTest() { Main m = new Main(); return m.g(); } /// CHECK-START: Main Main.newArrayRemoveTest() builder (after) /// CHECK: NewArray /// CHECK: ArrayGet /// CHECK-START: Main Main.newArrayRemoveTest() builder (after) /// CHECK-NOT: NullCheck public Main newArrayRemoveTest() { Main[] ms = new Main[1]; return ms[0]; } /// CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier (before) /// CHECK: NewInstance /// CHECK: NullCheck /// CHECK-START: Main Main.ifRemoveTest(boolean) instruction_simplifier (after) /// CHECK: NewInstance /// CHECK-NOT: NullCheck public Main ifRemoveTest(boolean flag) { Main m = null; if (flag) { m = new Main(); } else { m = new Main(1); } return m.g(); } /// CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier (before) /// CHECK: NewInstance /// CHECK: NullCheck /// CHECK-START: Main Main.ifKeepTest(boolean) instruction_simplifier (after) /// CHECK: NewInstance /// CHECK: NullCheck public Main ifKeepTest(boolean flag) { Main m = null; if (flag) { m = new Main(1); } return m.g(); } /// CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.forRemoveTest(int) instruction_simplifier (after) /// CHECK-NOT: NullCheck public Main forRemoveTest(int count) { Main a = new Main(); Main m = new Main(); for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = a; } } return m.g(); } /// CHECK-START: Main Main.forKeepTest(int) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.forKeepTest(int) instruction_simplifier (after) /// CHECK: NullCheck public Main forKeepTest(int count) { Main a = new Main(); Main m = new Main(); for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = a; } else { m = null; } } return m.g(); } /// CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.phiFlowRemoveTest(int) instruction_simplifier (after) /// CHECK-NOT: NullCheck public Main phiFlowRemoveTest(int count) { Main a = new Main(); Main m = new Main(); for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = a; } } Main n = new Main(); for (int i = 0; i < count; i++) { if (i % 3 == 0) { n = m; } } return n.g(); } /// CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.phiFlowKeepTest(int) instruction_simplifier (after) /// CHECK: NullCheck public Main phiFlowKeepTest(int count) { Main a = new Main(); Main m = new Main(); for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = a; } else { m = null; } } Main n = new Main(); for (int i = 0; i < count; i++) { if (i % 3 == 0) { n = m; } } return n.g(); } /// CHECK-START: Main Main.scopeRemoveTest(int, Main) builder (after) /// CHECK-NOT: NullCheck public Main scopeRemoveTest(int count, Main a) { Main m = null; for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = new Main(); m.g(); } else { m = a; } } return m; } /// CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.scopeKeepTest(int, Main) instruction_simplifier (after) /// CHECK: NullCheck public Main scopeKeepTest(int count, Main a) { Main m = new Main(); for (int i = 0; i < count; i++) { if (i % 2 == 0) { m = a; } else { m = a; m.g(); } } return m; } /// CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier (after) /// CHECK-NOT: NullCheck public Main scopeIfNotNullRemove(Main m) { if (m != null) { return m.g(); } return m; } /// CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier (after) /// CHECK: NullCheck public Main scopeIfKeep(Main m) { if (m == null) { m = new Main(); } return m.g(); } public Main() {} public Main(int unused) {} private Main g() { // avoids inlining throw new RuntimeException(); } public static void main(String[] args) { new Main(); } } // Regression for when we created and kept equivalent phis with the same type. // The phi used in comparison would be different then the one used for access // so we could not safely discard it. class ListElement { private ListElement next; /// CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier (before) /// CHECK: NullCheck /// CHECK: NullCheck /// CHECK-START: boolean ListElement.isShorter(ListElement, ListElement) instruction_simplifier (after) /// CHECK-NOT: NullCheck static boolean isShorter(ListElement x, ListElement y) { ListElement xTail = x; ListElement yTail = y; while (yTail != null) { if (xTail == null) return true; xTail = xTail.next; yTail = yTail.next; } return false; } }