1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package compiler.cha;
  25 
  26 import jdk.internal.vm.annotation.DontInline;
  27 import static compiler.cha.StrengthReduceInterfaceCall.*;
  28 
  29 public class TwoLevelHierarchyLinear extends ATest<TwoLevelHierarchyLinear.I> {
  30     public TwoLevelHierarchyLinear() {
  31         super(I.class, C.class);
  32     }
  33 
  34     interface J { default Object m() { return WRONG; } }
  35 
  36     interface I extends J { Object m(); }
  37     static class C implements I { public Object m() { return CORRECT; }}
  38 
  39     interface K1 extends I {}
  40     interface K2 extends I { Object m(); }
  41     interface K3 extends I { default Object m() { return WRONG; }}
  42 
  43     static class D implements I { public Object m() { return WRONG;   }}
  44 
  45     static class DJ1 implements J {}
  46     static class DJ2 implements J { public Object m() { return WRONG; }}
  47 
  48     @DontInline
  49     public Object test(I i) {
  50         return i.m();
  51     }
  52 
  53     @TestCase
  54     public void testMega1() {
  55         // 0. Trigger compilation of a megamorphic call site
  56         compile(megamorphic()); // C1,C2,C3 <: C.m <: intf I.m ABSTRACT <: intf J.m ABSTRACT
  57         assertCompiled();
  58 
  59         // Dependency: type = unique_concrete_method, context = I, method = C.m
  60 
  61         checkInvalidReceiver(); // ensure proper type check is preserved
  62 
  63         // 1. No deoptimization/invalidation on not-yet-seen receiver
  64         repeat(100, () -> call(new C(){})); // Cn <: C.m <: intf I.m ABSTRACT <: intf J.m DEFAULT
  65         assertCompiled();
  66 
  67         // 2. No dependency invalidation on class loading of unrelated classes: different context
  68         initialize(K1.class,   // intf  K1            <: intf I.m ABSTRACT <: intf J.m DEFAULT
  69                    K2.class,   // intf  K2.m ABSTRACT <: intf I.m ABSTRACT <: intf J.m DEFAULT
  70                    DJ1.class,  //      DJ1                                 <: intf J.m DEFAULT
  71                    DJ2.class); //      DJ2.m                               <: intf J.m DEFAULT
  72         assertCompiled();
  73 
  74         // 3. Dependency invalidation on D <: I
  75         initialize(D.class); // D.m <: intf I.m ABSTRACT <: intf J.m DEFAULT
  76         assertNotCompiled();
  77 
  78         // 4. Recompilation: no inlining, no dependencies
  79         compile(megamorphic());
  80         call(new C() { public Object m() { return CORRECT; }}); // Cn.m <: C.m <: intf I.m ABSTRACT <: intf J.m DEFAULT
  81         assertCompiled();
  82 
  83         checkInvalidReceiver(); // ensure proper type check on receiver is preserved
  84     }
  85 
  86     @TestCase
  87     public void testMega2() {
  88         // 0. Trigger compilation of a megamorphic call site
  89         compile(megamorphic()); // C1,C2,C3 <: C.m <: intf I.m ABSTRACT <: intf J.m DEFAULT
  90         assertCompiled();
  91 
  92         // Dependency: type = unique_concrete_method, context = I, method = C.m
  93 
  94         checkInvalidReceiver(); // ensure proper type check on receiver is preserved
  95 
  96         // 1. Dependency invalidation
  97         initialize(K3.class); // intf K3.m DEFAULT <: intf I.m ABSTRACT <: intf J.m DEFAULT
  98         assertNotCompiled();
  99 
 100         // 2. Recompilation: still inlines
 101         // FIXME: no default method support in CHA yet
 102         compile(megamorphic());
 103         call(new K3() { public Object m() { return CORRECT; }}); // K3n.m <: intf K3.m DEFAULT <: intf I.m ABSTRACT <: intf J.m ABSTRACT
 104         assertNotCompiled();
 105 
 106         // 3. Recompilation: no inlining, no dependencies
 107         compile(megamorphic());
 108         call(new K3() { public Object m() { return CORRECT; }}); // Kn.m <: intf K3.m DEFAULT  <: intf I.m ABSTRACT <: intf J.m DEFAULT
 109         assertCompiled();
 110 
 111         checkInvalidReceiver(); // ensure proper type check on receiver is preserved
 112     }
 113 
 114     @Override
 115     public void checkInvalidReceiver() {
 116         shouldThrow(IncompatibleClassChangeError.class, () -> {
 117             I o = (I) unsafeCastMH(I.class).invokeExact(new Object()); // unrelated
 118             test(o);
 119         });
 120         assertCompiled();
 121 
 122         shouldThrow(IncompatibleClassChangeError.class, () -> {
 123             I j = (I) unsafeCastMH(I.class).invokeExact((Object)new J() {}); // super interface
 124             test(j);
 125         });
 126         assertCompiled();
 127     }
 128 }
 129