content: /*
   * 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:  <<SubARet:i\d+>>      IntConstant 42
    /// CHECK:  <<Obj:l\d+>>          NullCheck
    /// CHECK:  <<ObjClass:l\d+>>     InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_
    /// CHECK:  <<InlineClass:l\d+>>  LoadClass class_name:SubA
    /// CHECK:  <<Test:z\d+>>         NotEqual [<<InlineClass>>,<<ObjClass>>]
    /// CHECK:  <<DefaultRet:i\d+>>   InvokeVirtual [<<Obj>>] method_name:Super.getValue
  
    /// CHECK:  <<Ret:i\d+>>          Phi [<<SubARet>>,<<DefaultRet>>]
    /// CHECK:                        Return [<<Ret>>]
  
    /// 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:  <<SubARet:i\d+>>          IntConstant 42
    /// CHECK-DAG:  <<SubBRet:i\d+>>          IntConstant 38
    /// CHECK-DAG:   <<Obj:l\d+>>             NullCheck
    /// CHECK-DAG:   <<ObjClassSubA:l\d+>>    InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_
    /// CHECK-DAG:   <<InlineClassSubA:l\d+>> LoadClass class_name:SubA
    /// CHECK-DAG:   <<TestSubA:z\d+>>        NotEqual [<<InlineClassSubA>>,<<ObjClassSubA>>]
    /// CHECK-DAG:                            If [<<TestSubA>>]
  
    /// CHECK-DAG:   <<ObjClassSubB:l\d+>>    InstanceFieldGet field_name:java.lang.Object.shadow$_klass_
    /// CHECK-DAG:   <<InlineClassSubB:l\d+>> LoadClass class_name:SubB
    /// CHECK-DAG:   <<TestSubB:z\d+>>        NotEqual [<<InlineClassSubB>>,<<ObjClassSubB>>]
    /// CHECK-DAG:   <<DefaultRet:i\d+>>      InvokeVirtual [<<Obj>>] method_name:Super.getValue
  
    /// CHECK-DAG:  <<FirstMerge:i\d+>>       Phi [<<SubBRet>>,<<DefaultRet>>]
    /// CHECK-DAG:  <<Ret:i\d+>>              Phi [<<SubARet>>,<<FirstMerge>>]
    /// CHECK-DAG:                            Return [<<Ret>>]
  
    /// 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:  <<SubARet:i\d+>>          IntConstant 42
    /// CHECK-DAG:  <<SubCRet:i\d+>>          IntConstant 24
    /// CHECK-DAG:  <<Obj:l\d+>>              NullCheck
    /// CHECK-DAG:  <<ObjClassSubA:l\d+>>     InstanceFieldGet [<<Obj>>] field_name:java.lang.Object.shadow$_klass_
    /// CHECK-DAG:  <<InlineClassSubA:l\d+>>  LoadClass class_name:SubA
    /// CHECK-DAG:  <<TestSubA:z\d+>>         NotEqual [<<InlineClassSubA>>,<<ObjClassSubA>>]
    /// CHECK-DAG:                            If [<<TestSubA>>]
  
    /// CHECK-DAG:  <<ObjClassSubC:l\d+>>     InstanceFieldGet field_name:java.lang.Object.shadow$_klass_
    /// CHECK-DAG:  <<InlineClassSubC:l\d+>>  LoadClass class_name:SubC
    /// CHECK-DAG:  <<TestSubC:z\d+>>         NotEqual [<<InlineClassSubC>>,<<ObjClassSubC>>]
    /// CHECK-DAG:  <<DefaultRet:i\d+>>       InvokeVirtual [<<Obj>>] method_name:Super.getValue
  
    /// CHECK-DAG:  <<FirstMerge:i\d+>>       Phi [<<SubCRet>>,<<DefaultRet>>]
    /// CHECK-DAG:  <<Ret:i\d+>>              Phi [<<SubARet>>,<<FirstMerge>>]
    /// CHECK-DAG:                            Return [<<Ret>>]
  
    /// 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();
    }
  
  }
  