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 */
23package org.graalvm.compiler.core.test.tutorial;
24
25import java.lang.reflect.Field;
26import java.lang.reflect.Method;
27import java.util.Arrays;
28import java.util.Collection;
29
30import jdk.vm.ci.meta.MetaAccessProvider;
31import jdk.vm.ci.meta.ResolvedJavaField;
32import jdk.vm.ci.meta.ResolvedJavaMethod;
33import jdk.vm.ci.meta.ResolvedJavaType;
34
35import org.junit.Assert;
36import org.junit.Test;
37
38import org.graalvm.compiler.api.test.Graal;
39import org.graalvm.compiler.core.target.Backend;
40import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.MethodState;
41import org.graalvm.compiler.core.test.tutorial.StaticAnalysis.TypeFlow;
42import org.graalvm.compiler.nodes.spi.StampProvider;
43import org.graalvm.compiler.phases.util.Providers;
44import org.graalvm.compiler.runtime.RuntimeProvider;
45
46public 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}
216