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