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