/* * Copyright (C) 2017 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. */ class SubA extends Super { int getValue() { return 42; } } class SubB extends Super { int getValue() { return 38; } } class SubD extends Super { int getValue() { return 10; } } class SubE extends Super { int getValue() { return -4; } } public class Main { /// CHECK-START: int Main.inlineMonomorphicSubA(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue /// CHECK-START: int Main.inlineMonomorphicSubA(Super) inliner (after) /// CHECK: <> IntConstant 42 /// CHECK: <> NullCheck /// CHECK: <> InstanceFieldGet [<>] field_name:java.lang.Object.shadow$_klass_ /// CHECK: <> LoadClass class_name:SubA /// CHECK: <> NotEqual [<>,<>] /// CHECK: <> InvokeVirtual [<>] method_name:Super.getValue /// CHECK: <> Phi [<>,<>] /// CHECK: Return [<>] /// CHECK-NOT: Deoptimize public static int inlineMonomorphicSubA(Super a) { return a.getValue(); } /// CHECK-START: int Main.inlinePolymophicSubASubB(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue // Note that the order in which the types are added to the inline cache in the profile matters. /// CHECK-START: int Main.inlinePolymophicSubASubB(Super) inliner (after) /// CHECK-DAG: <> IntConstant 42 /// CHECK-DAG: <> IntConstant 38 /// CHECK-DAG: <> NullCheck /// CHECK-DAG: <> InstanceFieldGet [<>] field_name:java.lang.Object.shadow$_klass_ /// CHECK-DAG: <> LoadClass class_name:SubA /// CHECK-DAG: <> NotEqual [<>,<>] /// CHECK-DAG: If [<>] /// CHECK-DAG: <> InstanceFieldGet field_name:java.lang.Object.shadow$_klass_ /// CHECK-DAG: <> LoadClass class_name:SubB /// CHECK-DAG: <> NotEqual [<>,<>] /// CHECK-DAG: <> InvokeVirtual [<>] method_name:Super.getValue /// CHECK-DAG: <> Phi [<>,<>] /// CHECK-DAG: <> Phi [<>,<>] /// CHECK-DAG: Return [<>] /// CHECK-NOT: Deoptimize public static int inlinePolymophicSubASubB(Super a) { return a.getValue(); } /// CHECK-START: int Main.inlinePolymophicCrossDexSubASubC(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue // Note that the order in which the types are added to the inline cache in the profile matters. /// CHECK-START: int Main.inlinePolymophicCrossDexSubASubC(Super) inliner (after) /// CHECK-DAG: <> IntConstant 42 /// CHECK-DAG: <> IntConstant 24 /// CHECK-DAG: <> NullCheck /// CHECK-DAG: <> InstanceFieldGet [<>] field_name:java.lang.Object.shadow$_klass_ /// CHECK-DAG: <> LoadClass class_name:SubA /// CHECK-DAG: <> NotEqual [<>,<>] /// CHECK-DAG: If [<>] /// CHECK-DAG: <> InstanceFieldGet field_name:java.lang.Object.shadow$_klass_ /// CHECK-DAG: <> LoadClass class_name:SubC /// CHECK-DAG: <> NotEqual [<>,<>] /// CHECK-DAG: <> InvokeVirtual [<>] method_name:Super.getValue /// CHECK-DAG: <> Phi [<>,<>] /// CHECK-DAG: <> Phi [<>,<>] /// CHECK-DAG: Return [<>] /// CHECK-NOT: Deoptimize public static int inlinePolymophicCrossDexSubASubC(Super a) { return a.getValue(); } /// CHECK-START: int Main.inlineMegamorphic(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue /// CHECK-START: int Main.inlineMegamorphic(Super) inliner (after) /// CHECK: InvokeVirtual method_name:Super.getValue public static int inlineMegamorphic(Super a) { return a.getValue(); } /// CHECK-START: int Main.inlineMissingTypes(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue /// CHECK-START: int Main.inlineMissingTypes(Super) inliner (after) /// CHECK: InvokeVirtual method_name:Super.getValue public static int inlineMissingTypes(Super a) { return a.getValue(); } /// CHECK-START: int Main.noInlineCache(Super) inliner (before) /// CHECK: InvokeVirtual method_name:Super.getValue /// CHECK-START: int Main.noInlineCache(Super) inliner (after) /// CHECK: InvokeVirtual method_name:Super.getValue public static int noInlineCache(Super a) { return a.getValue(); } public static void testInlineMonomorphic() { if (inlineMonomorphicSubA(new SubA()) != 42) { throw new Error("Expected 42"); } // Call with a different type than the one from the inline cache. if (inlineMonomorphicSubA(new SubB()) != 38) { throw new Error("Expected 38"); } } public static void testInlinePolymorhic() { if (inlinePolymophicSubASubB(new SubA()) != 42) { throw new Error("Expected 42"); } if (inlinePolymophicSubASubB(new SubB()) != 38) { throw new Error("Expected 38"); } // Call with a different type than the one from the inline cache. if (inlinePolymophicSubASubB(new SubC()) != 24) { throw new Error("Expected 25"); } if (inlinePolymophicCrossDexSubASubC(new SubA()) != 42) { throw new Error("Expected 42"); } if (inlinePolymophicCrossDexSubASubC(new SubC()) != 24) { throw new Error("Expected 24"); } // Call with a different type than the one from the inline cache. if (inlinePolymophicCrossDexSubASubC(new SubB()) != 38) { throw new Error("Expected 38"); } } public static void testInlineMegamorphic() { if (inlineMegamorphic(new SubA()) != 42) { throw new Error("Expected 42"); } } public static void testNoInlineCache() { if (noInlineCache(new SubA()) != 42) { throw new Error("Expected 42"); } } public static void main(String[] args) { testInlineMonomorphic(); testInlinePolymorhic(); testInlineMegamorphic(); testNoInlineCache(); } }