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