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  */
  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 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 }