1 /*
   2  * Copyright (c) 2015, 2015, 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 package org.graalvm.compiler.core.test.tutorial;
  24 
  25 import java.lang.reflect.Field;
  26 import java.lang.reflect.Method;
  27 import java.util.Arrays;
  28 import java.util.Collection;
  29 
  30 import jdk.vm.ci.meta.MetaAccessProvider;
  31 import jdk.vm.ci.meta.ResolvedJavaField;
  32 import jdk.vm.ci.meta.ResolvedJavaMethod;
  33 import jdk.vm.ci.meta.ResolvedJavaType;
  34 
  35 import org.junit.Assert;
  36 import org.junit.Test;
  37 
  38 import org.graalvm.compiler.api.test.Graal;
  39 import org.graalvm.compiler.core.target.Backend;
  40 import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.MethodState;
  41 import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.TypeFlow;
  42 import org.graalvm.compiler.nodes.spi.StampProvider;
  43 import org.graalvm.compiler.phases.util.Providers;
  44 import org.graalvm.compiler.runtime.RuntimeProvider;
  45 
  46 public class StaticAnalysisTests {
  47 
  48     static class A {
  49         Object foo(Object arg) {
  50             return arg;
  51         }
  52     }
  53 
  54     static class B extends A {
  55         @Override
  56         Object foo(Object arg) {
  57             if (arg instanceof Data) {
  58                 return ((Data) arg).f;
  59             } else {
  60                 return super.foo(arg);
  61             }
  62         }
  63     }
  64 
  65     static class Data {
  66         Object f;
  67     }
  68 
  69     private final MetaAccessProvider metaAccess;
  70     private final StampProvider stampProvider;
  71 
  72     public StaticAnalysisTests() {
  73         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
  74         Providers providers = backend.getProviders();
  75         this.metaAccess = providers.getMetaAccess();
  76         this.stampProvider = providers.getStampProvider();
  77     }
  78 
  79     static void test01Entry() {
  80         A a = new A();
  81         a.foo(null);
  82     }
  83 
  84     @Test
  85     public void test01() {
  86         StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
  87         sa.addMethod(findMethod(StaticAnalysisTests.class, "test01Entry"));
  88         sa.finish();
  89 
  90         assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class));
  91         assertEquals(f(sa, Data.class, "f"));
  92         assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
  93         assertEquals(m(sa, A.class, "foo").getFormalParameters()[1]);
  94         assertEquals(m(sa, A.class, "foo").getFormalReturn());
  95     }
  96 
  97     static void test02Entry() {
  98         A a = new A();
  99         a.foo(new Data());
 100 
 101         B b = new B();
 102         b.foo(null);
 103     }
 104 
 105     @Test
 106     public void test02() {
 107         StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
 108         sa.addMethod(findMethod(StaticAnalysisTests.class, "test02Entry"));
 109         sa.finish();
 110 
 111         assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class));
 112         assertEquals(f(sa, Data.class, "f"));
 113         assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
 114         assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
 115         assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
 116         assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
 117         assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
 118         assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class));
 119     }
 120 
 121     static void test03Entry() {
 122         Data data = new Data();
 123         data.f = new Integer(42);
 124 
 125         A a = new A();
 126         a.foo(new Data());
 127 
 128         B b = new B();
 129         b.foo(null);
 130     }
 131 
 132     @Test
 133     public void test03() {
 134         StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
 135         sa.addMethod(findMethod(StaticAnalysisTests.class, "test03Entry"));
 136         sa.finish();
 137 
 138         assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(B.class), t(Data.class), t(Integer.class));
 139         assertEquals(f(sa, Data.class, "f"), t(Integer.class));
 140         assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class), t(B.class));
 141         assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
 142         assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
 143         assertEquals(m(sa, B.class, "foo").getFormalParameters()[0], t(B.class));
 144         assertEquals(m(sa, B.class, "foo").getFormalParameters()[1]);
 145         assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class));
 146     }
 147 
 148     static void test04Entry() {
 149         Data data = null;
 150         for (int i = 0; i < 2; i++) {
 151             if (i == 0) {
 152                 data = new Data();
 153             } else if (i == 1) {
 154                 data.f = new Integer(42);
 155             }
 156         }
 157 
 158         A a = new A();
 159         a.foo(data);
 160     }
 161 
 162     @Test
 163     public void test04() {
 164         StaticAnalysis sa = new StaticAnalysis(metaAccess, stampProvider);
 165         sa.addMethod(findMethod(StaticAnalysisTests.class, "test04Entry"));
 166         sa.finish();
 167 
 168         assertEquals(sa.getResults().getAllInstantiatedTypes(), t(A.class), t(Data.class), t(Integer.class));
 169         assertEquals(f(sa, Data.class, "f"), t(Integer.class));
 170         assertEquals(m(sa, A.class, "foo").getFormalParameters()[0], t(A.class));
 171         assertEquals(m(sa, A.class, "foo").getFormalParameters()[1], t(Data.class));
 172         assertEquals(m(sa, A.class, "foo").getFormalReturn(), t(Data.class));
 173     }
 174 
 175     private MethodState m(StaticAnalysis sa, Class<?> declaringClass, String name) {
 176         return sa.getResults().lookupMethod(findMethod(declaringClass, name));
 177     }
 178 
 179     private TypeFlow f(StaticAnalysis sa, Class<?> declaringClass, String name) {
 180         return sa.getResults().lookupField(findField(declaringClass, name));
 181     }
 182 
 183     private static void assertEquals(TypeFlow actual, Object... expected) {
 184         Collection<?> actualTypes = actual.getTypes();
 185         if (actualTypes.size() != expected.length || !actualTypes.containsAll(Arrays.asList(expected))) {
 186             Assert.fail(actualTypes + " != " + Arrays.asList(expected));
 187         }
 188     }
 189 
 190     private ResolvedJavaType t(Class<?> clazz) {
 191         return metaAccess.lookupJavaType(clazz);
 192     }
 193 
 194     private ResolvedJavaMethod findMethod(Class<?> declaringClass, String name) {
 195         Method reflectionMethod = null;
 196         for (Method m : declaringClass.getDeclaredMethods()) {
 197             if (m.getName().equals(name)) {
 198                 assert reflectionMethod == null : "More than one method with name " + name + " in class " + declaringClass.getName();
 199                 reflectionMethod = m;
 200             }
 201         }
 202         assert reflectionMethod != null : "No method with name " + name + " in class " + declaringClass.getName();
 203         return metaAccess.lookupJavaMethod(reflectionMethod);
 204     }
 205 
 206     private ResolvedJavaField findField(Class<?> declaringClass, String name) {
 207         Field reflectionField;
 208         try {
 209             reflectionField = declaringClass.getDeclaredField(name);
 210         } catch (NoSuchFieldException | SecurityException ex) {
 211             throw new AssertionError(ex);
 212         }
 213         return metaAccess.lookupJavaField(reflectionField);
 214     }
 215 }