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