1 /*
   2  * Copyright (c) 2011, 2018, 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          */
  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          */
  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 
  78         public InvocationPlugins getInvocationPlugins() {
  79             return invocationPlugins;
  80         }
  81 
  82         public NodePlugin[] getNodePlugins() {
  83             return nodePlugins;
  84         }
  85 
  86         public void appendNodePlugin(NodePlugin plugin) {
  87             nodePlugins = Arrays.copyOf(nodePlugins, nodePlugins.length + 1);
  88             nodePlugins[nodePlugins.length - 1] = plugin;
  89         }
  90 
  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 
  98         public void clearNodePlugin() {
  99             nodePlugins = new NodePlugin[0];
 100         }
 101 
 102         public ParameterPlugin[] getParameterPlugins() {
 103             return parameterPlugins;
 104         }
 105 
 106         public void appendParameterPlugin(ParameterPlugin plugin) {
 107             parameterPlugins = Arrays.copyOf(parameterPlugins, parameterPlugins.length + 1);
 108             parameterPlugins[parameterPlugins.length - 1] = plugin;
 109         }
 110 
 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 
 118         public TypePlugin[] getTypePlugins() {
 119             return typePlugins;
 120         }
 121 
 122         public void appendTypePlugin(TypePlugin plugin) {
 123             typePlugins = Arrays.copyOf(typePlugins, typePlugins.length + 1);
 124             typePlugins[typePlugins.length - 1] = plugin;
 125         }
 126 
 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 
 134         public void clearParameterPlugin() {
 135             parameterPlugins = new ParameterPlugin[0];
 136         }
 137 
 138         public InlineInvokePlugin[] getInlineInvokePlugins() {
 139             return inlineInvokePlugins;
 140         }
 141 
 142         public void appendInlineInvokePlugin(InlineInvokePlugin plugin) {
 143             inlineInvokePlugins = Arrays.copyOf(inlineInvokePlugins, inlineInvokePlugins.length + 1);
 144             inlineInvokePlugins[inlineInvokePlugins.length - 1] = plugin;
 145         }
 146 
 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 
 154         public void clearInlineInvokePlugins() {
 155             inlineInvokePlugins = new InlineInvokePlugin[0];
 156         }
 157 
 158         public LoopExplosionPlugin getLoopExplosionPlugin() {
 159             return loopExplosionPlugin;
 160         }
 161 
 162         public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
 163             this.loopExplosionPlugin = plugin;
 164         }
 165 
 166         public ClassInitializationPlugin getClassInitializationPlugin() {
 167             return classInitializationPlugin;
 168         }
 169 
 170         public void setClassInitializationPlugin(ClassInitializationPlugin plugin) {
 171             this.classInitializationPlugin = plugin;
 172         }
 173 
 174         public InvokeDynamicPlugin getInvokeDynamicPlugin() {
 175             return invokeDynamicPlugin;
 176         }
 177 
 178         public void setInvokeDynamicPlugin(InvokeDynamicPlugin plugin) {
 179             this.invokeDynamicPlugin = plugin;
 180         }
 181 
 182         public ProfilingPlugin getProfilingPlugin() {
 183             return profilingPlugin;
 184         }
 185 
 186         public void setProfilingPlugin(ProfilingPlugin plugin) {
 187             this.profilingPlugin = plugin;
 188         }
 189 
 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 
 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      */
 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      */
 262     public GraphBuilderConfiguration withUnresolvedIsError(boolean newUnresolvedIsError) {
 263         return new GraphBuilderConfiguration(eagerResolving, newUnresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
 264                         plugins);
 265     }
 266 
 267     public GraphBuilderConfiguration withEagerResolving(boolean newEagerResolving) {
 268         return new GraphBuilderConfiguration(newEagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
 269                         plugins);
 270     }
 271 
 272     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
 273         return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, newSkippedExceptionTypes,
 274                         plugins);
 275     }
 276 
 277     public GraphBuilderConfiguration withBytecodeExceptionMode(BytecodeExceptionMode newBytecodeExceptionMode) {
 278         return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, newBytecodeExceptionMode, omitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
 279                         plugins);
 280     }
 281 
 282     public GraphBuilderConfiguration withOmitAssertions(boolean newOmitAssertions) {
 283         return new GraphBuilderConfiguration(eagerResolving, unresolvedIsError, bytecodeExceptionMode, newOmitAssertions, insertFullInfopoints, trackNodeSourcePosition, skippedExceptionTypes,
 284                         plugins);
 285     }
 286 
 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 
 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 
 299     public ResolvedJavaType[] getSkippedExceptionTypes() {
 300         return skippedExceptionTypes;
 301     }
 302 
 303     public boolean eagerResolving() {
 304         return eagerResolving;
 305     }
 306 
 307     public BytecodeExceptionMode getBytecodeExceptionMode() {
 308         return bytecodeExceptionMode;
 309     }
 310 
 311     public boolean omitAssertions() {
 312         return omitAssertions;
 313     }
 314 
 315     public boolean trackNodeSourcePosition() {
 316         return trackNodeSourcePosition;
 317     }
 318 
 319     public boolean insertFullInfopoints() {
 320         return insertFullInfopoints;
 321     }
 322 
 323     public static GraphBuilderConfiguration getDefault(Plugins plugins) {
 324         return new GraphBuilderConfiguration(false, false, BytecodeExceptionMode.Profile, false, false, false, EMPTY, plugins);
 325     }
 326 
 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. */
 332     public boolean unresolvedIsError() {
 333         return unresolvedIsError;
 334     }
 335 
 336     public Plugins getPlugins() {
 337         return plugins;
 338     }
 339 }