1/*
2 * Copyright (c) 2011, 2016, 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.nodes.graphbuilderconf;
24
25import java.util.Arrays;
26
27import org.graalvm.compiler.core.common.type.StampPair;
28
29import jdk.vm.ci.meta.JavaType;
30import jdk.vm.ci.meta.ResolvedJavaType;
31
32public class GraphBuilderConfiguration {
33
34    public static class Plugins {
35        private final InvocationPlugins invocationPlugins;
36        private NodePlugin[] nodePlugins;
37        private ParameterPlugin[] parameterPlugins;
38        private TypePlugin[] typePlugins;
39        private InlineInvokePlugin[] inlineInvokePlugins;
40        private LoopExplosionPlugin loopExplosionPlugin;
41        private ClassInitializationPlugin classInitializationPlugin;
42        private ProfilingPlugin profilingPlugin;
43
44        /**
45         * Creates a copy of a given set of plugins. The {@link InvocationPlugins} in
46         * {@code copyFrom} become the {@linkplain InvocationPlugins#getParent() default}
47         * {@linkplain #getInvocationPlugins() invocation plugins} in this object.
48         */
49        public Plugins(Plugins copyFrom) {
50            this.invocationPlugins = new InvocationPlugins(copyFrom.invocationPlugins);
51            this.nodePlugins = copyFrom.nodePlugins;
52            this.parameterPlugins = copyFrom.parameterPlugins;
53            this.typePlugins = copyFrom.typePlugins;
54            this.inlineInvokePlugins = copyFrom.inlineInvokePlugins;
55            this.loopExplosionPlugin = copyFrom.loopExplosionPlugin;
56            this.classInitializationPlugin = copyFrom.classInitializationPlugin;
57            this.profilingPlugin = copyFrom.profilingPlugin;
58        }
59
60        /**
61         * Creates a new set of plugins.
62         *
63         * @param invocationPlugins the {@linkplain #getInvocationPlugins() invocation plugins} in
64         *            this object
65         */
66        public Plugins(InvocationPlugins invocationPlugins) {
67            this.invocationPlugins = invocationPlugins;
68            this.nodePlugins = new NodePlugin[0];
69            this.parameterPlugins = new ParameterPlugin[0];
70            this.typePlugins = new TypePlugin[0];
71            this.inlineInvokePlugins = new InlineInvokePlugin[0];
72        }
73
74        public InvocationPlugins getInvocationPlugins() {
75            return invocationPlugins;
76        }
77
78        public NodePlugin[] getNodePlugins() {
79            return nodePlugins;
80        }
81
82        public void appendNodePlugin(NodePlugin plugin) {
83            nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1);
84            nodePlugins[nodePlugins.length - 1] = plugin;
85        }
86
87        public void prependNodePlugin(NodePlugin plugin) {
88            NodePlugin[] newPlugins = new NodePlugin[nodePlugins.length + 1];
89            System.arraycopy(nodePlugins, 0, newPlugins, 1, nodePlugins.length);
90            newPlugins[0] = plugin;
91            nodePlugins = newPlugins;
92        }
93
94        public void clearNodePlugin() {
95            nodePlugins = new NodePlugin[0];
96        }
97
98        public ParameterPlugin[] getParameterPlugins() {
99            return parameterPlugins;
100        }
101
102        public void appendParameterPlugin(ParameterPlugin plugin) {
103            parameterPlugins = Arrays.copyOf(parameterPlugins, parameterPlugins.length + 1);
104            parameterPlugins[parameterPlugins.length - 1] = plugin;
105        }
106
107        public void prependParameterPlugin(ParameterPlugin plugin) {
108            ParameterPlugin[] newPlugins = new ParameterPlugin[parameterPlugins.length + 1];
109            System.arraycopy(parameterPlugins, 0, newPlugins, 1, parameterPlugins.length);
110            newPlugins[0] = plugin;
111            parameterPlugins = newPlugins;
112        }
113
114        public TypePlugin[] getTypePlugins() {
115            return typePlugins;
116        }
117
118        public void appendTypePlugin(TypePlugin plugin) {
119            typePlugins = Arrays.copyOf(typePlugins, typePlugins.length + 1);
120            typePlugins[typePlugins.length - 1] = plugin;
121        }
122
123        public void prependTypePlugin(TypePlugin plugin) {
124            TypePlugin[] newPlugins = new TypePlugin[typePlugins.length + 1];
125            System.arraycopy(typePlugins, 0, newPlugins, 1, typePlugins.length);
126            newPlugins[0] = plugin;
127            typePlugins = newPlugins;
128        }
129
130        public void clearParameterPlugin() {
131            parameterPlugins = new ParameterPlugin[0];
132        }
133
134        public InlineInvokePlugin[] getInlineInvokePlugins() {
135            return inlineInvokePlugins;
136        }
137
138        public void appendInlineInvokePlugin(InlineInvokePlugin plugin) {
139            inlineInvokePlugins = Arrays.copyOf(inlineInvokePlugins, inlineInvokePlugins.length + 1);
140            inlineInvokePlugins[inlineInvokePlugins.length - 1] = plugin;
141        }
142
143        public void prependInlineInvokePlugin(InlineInvokePlugin plugin) {
144            InlineInvokePlugin[] newPlugins = new InlineInvokePlugin[inlineInvokePlugins.length + 1];
145            System.arraycopy(inlineInvokePlugins, 0, newPlugins, 1, inlineInvokePlugins.length);
146            newPlugins[0] = plugin;
147            inlineInvokePlugins = newPlugins;
148        }
149
150        public void clearInlineInvokePlugins() {
151            inlineInvokePlugins = new InlineInvokePlugin[0];
152        }
153
154        public LoopExplosionPlugin getLoopExplosionPlugin() {
155            return loopExplosionPlugin;
156        }
157
158        public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
159            this.loopExplosionPlugin = plugin;
160        }
161
162        public ClassInitializationPlugin getClassInitializationPlugin() {
163            return classInitializationPlugin;
164        }
165
166        public void setClassInitializationPlugin(ClassInitializationPlugin plugin) {
167            this.classInitializationPlugin = plugin;
168        }
169
170        public ProfilingPlugin getProfilingPlugin() {
171            return profilingPlugin;
172        }
173
174        public void setProfilingPlugin(ProfilingPlugin plugin) {
175            this.profilingPlugin = plugin;
176        }
177
178        public StampPair getOverridingStamp(GraphBuilderTool b, JavaType type, boolean nonNull) {
179            for (TypePlugin plugin : getTypePlugins()) {
180                StampPair stamp = plugin.interceptType(b, type, nonNull);
181                if (stamp != null) {
182                    return stamp;
183                }
184            }
185            return null;
186        }
187    }
188
189    private static final ResolvedJavaType[] EMPTY = new ResolvedJavaType[]{};
190
191    private final boolean eagerResolving;
192    private final BytecodeExceptionMode bytecodeExceptionMode;
193    private final boolean omitAssertions;
194    private final ResolvedJavaType[] skippedExceptionTypes;
195    private final boolean insertFullInfopoints;
196    private final boolean trackNodeSourcePosition;
197    private final Plugins plugins;
198
199    public enum BytecodeExceptionMode {
200        /**
201         * This mode always explicitly checks for exceptions.
202         */
203        CheckAll,
204        /**
205         * This mode omits all explicit exception edges.
206         */
207        OmitAll,
208        /**
209         * This mode omits exception edges at invokes, but not for implicit null checks or bounds
210         * checks.
211         */
212        ExplicitOnly,
213        /**
214         * This mode uses profiling information to decide whether to use explicit exception edges.
215         */
216        Profile
217    }
218
219    protected GraphBuilderConfiguration(boolean eagerResolving, BytecodeExceptionMode bytecodeExceptionMode, boolean omitAssertions, boolean insertFullInfopoints,
220                    boolean trackNodeSourcePosition, ResolvedJavaType[] skippedExceptionTypes,
221                    Plugins plugins) {
222        this.eagerResolving = eagerResolving;
223        this.bytecodeExceptionMode = bytecodeExceptionMode;
224        this.omitAssertions = omitAssertions;
225        this.insertFullInfopoints = insertFullInfopoints;
226        this.trackNodeSourcePosition = trackNodeSourcePosition;
227        this.skippedExceptionTypes = skippedExceptionTypes;
228        this.plugins = plugins;
229    }
230
231    /**
232     * Creates a copy of this configuration with all its plugins. The {@link InvocationPlugins} in
233     * this configuration become the {@linkplain InvocationPlugins#getParent() parent} of the
234     * {@link InvocationPlugins} in the copy.
235     */
236    public GraphBuilderConfiguration copy() {
237        Plugins newPlugins = new Plugins(plugins);
238        GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
239                        newPlugins);
240        return result;
241    }
242
243    public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
244        return new GraphBuilderConfiguration(newEagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
245    }
246
247    public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
248        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
249    }
250
251    public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) {
252        return new GraphBuilderConfiguration(eagerResolving, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
253    }
254
255    public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
256        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes, plugins);
257    }
258
259    public GraphBuilderConfiguration withFullInfopoints(boolean newInsertFullInfopoints) {
260        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
261        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, newInsertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes, plugins);
262    }
263
264    public GraphBuilderConfiguration withNodeSourcePosition(boolean newTrackNodeSourcePosition) {
265        ResolvedJavaType[] newSkippedExceptionTypes = skippedExceptionTypes == EMPTY ? EMPTY : Arrays.copyOf(skippedExceptionTypes, skippedExceptionTypes.length);
266        return new GraphBuilderConfiguration(eagerResolving, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, newTrackNodeSourcePosition, newSkippedExceptionTypes, plugins);
267    }
268
269    public ResolvedJavaType[] getSkippedExceptionTypes() {
270        return skippedExceptionTypes;
271    }
272
273    public boolean eagerResolving() {
274        return eagerResolving;
275    }
276
277    public BytecodeExceptionMode getBytecodeExceptionMode() {
278        return bytecodeExceptionMode;
279    }
280
281    public boolean omitAssertions() {
282        return omitAssertions;
283    }
284
285    public boolean trackNodeSourcePosition() {
286        return trackNodeSourcePosition;
287    }
288
289    public boolean insertFullInfopoints() {
290        return insertFullInfopoints;
291    }
292
293    public static GraphBuilderConfiguration getDefault(Plugins plugins) {
294        return new GraphBuilderConfiguration(false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
295    }
296
297    public static GraphBuilderConfiguration getSnippetDefault(Plugins plugins) {
298        return new GraphBuilderConfiguration(true, BytecodeExceptionMode.OmitAll, false, false, false, EMPTY, plugins);
299    }
300
301    /**
302     * Returns {@code true} if it is an error for a class/field/method resolution to fail. The
303     * default is the same result as returned by {@link #eagerResolving()}. However, it may be
304     * overridden to allow failure even when {@link #eagerResolving} is {@code true}.
305     */
306    public boolean unresolvedIsError() {
307        return eagerResolving;
308    }
309
310    public Plugins getPlugins() {
311        return plugins;
312    }
313}
314