1 /*
   2  * Copyright (c) 2015, 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 static jdk.vm.ci.code.BytecodeFrame.AFTER_BCI;
  26 import static jdk.vm.ci.code.BytecodeFrame.AFTER_EXCEPTION_BCI;
  27 import static jdk.vm.ci.code.BytecodeFrame.BEFORE_BCI;
  28 import static jdk.vm.ci.code.BytecodeFrame.INVALID_FRAMESTATE_BCI;
  29 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
  30 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
  31 
  32 import org.graalvm.compiler.bytecode.BytecodeProvider;
  33 import org.graalvm.compiler.graph.NodeSourcePosition;
  34 import org.graalvm.compiler.nodes.AbstractMergeNode;
  35 import org.graalvm.compiler.nodes.FrameState;
  36 import org.graalvm.compiler.nodes.Invoke;
  37 import org.graalvm.compiler.nodes.StateSplit;
  38 import org.graalvm.compiler.nodes.StructuredGraph;
  39 import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
  40 
  41 import jdk.vm.ci.meta.ResolvedJavaMethod;
  42 
  43 /**
  44  * An intrinsic is a substitute implementation of a Java method (or a bytecode in the case of
  45  * snippets) that is itself implemented in Java. This interface provides information about the
  46  * intrinsic currently being processed by the graph builder.
  47  *
  48  * When in the scope of an intrinsic, the graph builder does not check the value kinds flowing
  49  * through the JVM state since intrinsics can employ non-Java kinds to represent values such as raw
  50  * machine words and pointers.
  51  */
  52 public class IntrinsicContext {
  53 
  54     /**
  55      * Method being intrinsified.
  56      */
  57     final ResolvedJavaMethod method;
  58 
  59     /**
  60      * Method providing the intrinsic implementation.
  61      */
  62     final ResolvedJavaMethod intrinsic;
  63 
  64     /**
  65      * Provider of bytecode to be parsed for a method that is part of an intrinsic.
  66      */
  67     final BytecodeProvider bytecodeProvider;
  68 
  69     final CompilationContext compilationContext;
  70 
  71     final boolean allowPartialIntrinsicArgumentMismatch;
  72 
  73     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
  74         this(method, intrinsic, bytecodeProvider, compilationContext, false);
  75     }
  76 
  77     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext,
  78                     boolean allowPartialIntrinsicArgumentMismatch) {
  79         this.method = method;
  80         this.intrinsic = intrinsic;
  81         this.bytecodeProvider = bytecodeProvider;
  82         assert bytecodeProvider != null;
  83         this.compilationContext = compilationContext;
  84         this.allowPartialIntrinsicArgumentMismatch = allowPartialIntrinsicArgumentMismatch;
  85         assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
  86     }
  87 
  88     /**
  89      * A partial intrinsic exits by (effectively) calling the intrinsified method. Normally, this
  90      * call must use exactly the same arguments as the call that is being intrinsified. This allows
  91      * to override this behavior.
  92      */
  93     public boolean allowPartialIntrinsicArgumentMismatch() {
  94         return allowPartialIntrinsicArgumentMismatch;
  95     }
  96 
  97     /**
  98      * Gets the method being intrinsified.
  99      */
 100     public ResolvedJavaMethod getOriginalMethod() {
 101         return method;
 102     }
 103 
 104     /**
 105      * Gets the method providing the intrinsic implementation.
 106      */
 107     public ResolvedJavaMethod getIntrinsicMethod() {
 108         return intrinsic;
 109     }
 110 
 111     /**
 112      * Gets provider of bytecode to be parsed for a method that is part of an intrinsic.
 113      */
 114     public BytecodeProvider getBytecodeProvider() {
 115         return bytecodeProvider;
 116     }
 117 
 118     /**
 119      * Determines if a call within the compilation scope of this intrinsic represents a call to the
 120      * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
 121      * intrinsification falls back to the original method.
 122      */
 123     public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
 124         return method.equals(targetMethod) || intrinsic.equals(targetMethod);
 125     }
 126 
 127     public boolean isPostParseInlined() {
 128         return compilationContext.equals(INLINE_AFTER_PARSING);
 129     }
 130 
 131     public boolean isCompilationRoot() {
 132         return compilationContext.equals(ROOT_COMPILATION);
 133     }
 134 
 135     /**
 136      * Denotes the compilation context in which an intrinsic is being parsed.
 137      */
 138     public enum CompilationContext {
 139         /**
 140          * An intrinsic is being processed when parsing an invoke bytecode that calls the
 141          * intrinsified method.
 142          */
 143         INLINE_DURING_PARSING,
 144 
 145         /**
 146          * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
 147          */
 148         INLINE_AFTER_PARSING,
 149 
 150         /**
 151          * An intrinsic is the root of compilation.
 152          */
 153         ROOT_COMPILATION
 154     }
 155 
 156     /**
 157      * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
 158      * are control flow predecessors of the current point in a graph.
 159      */
 160     public interface SideEffectsState {
 161 
 162         /**
 163          * Determines if the current program point is preceded by one or more side effects.
 164          */
 165         boolean isAfterSideEffect();
 166 
 167         /**
 168          * Gets the side effects preceding the current program point.
 169          */
 170         Iterable<StateSplit> sideEffects();
 171 
 172         /**
 173          * Records a side effect for the current program point.
 174          */
 175         void addSideEffect(StateSplit sideEffect);
 176     }
 177 
 178     public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit, NodeSourcePosition sourcePosition) {
 179         assert forStateSplit != graph.start();
 180         if (forStateSplit.hasSideEffect()) {
 181             if (sideEffects.isAfterSideEffect()) {
 182                 // Only the last side effect on any execution path in a replacement
 183                 // can inherit the stateAfter of the replaced node
 184                 FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
 185                 invalid.setNodeSourcePosition(sourcePosition);
 186                 for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
 187                     lastSideEffect.setStateAfter(invalid);
 188                 }
 189             }
 190             sideEffects.addSideEffect(forStateSplit);
 191             FrameState frameState;
 192             if (forStateSplit instanceof ExceptionObjectNode) {
 193                 frameState = graph.add(new FrameState(AFTER_EXCEPTION_BCI, (ExceptionObjectNode) forStateSplit));
 194             } else {
 195                 frameState = graph.add(new FrameState(AFTER_BCI));
 196             }
 197             frameState.setNodeSourcePosition(sourcePosition);
 198             return frameState;
 199         } else {
 200             if (forStateSplit instanceof AbstractMergeNode) {
 201                 // Merge nodes always need a frame state
 202                 if (sideEffects.isAfterSideEffect()) {
 203                     // A merge after one or more side effects
 204                     FrameState frameState = graph.add(new FrameState(AFTER_BCI));
 205                     frameState.setNodeSourcePosition(sourcePosition);
 206                     return frameState;
 207                 } else {
 208                     // A merge before any side effects
 209                     FrameState frameState = graph.add(new FrameState(BEFORE_BCI));
 210                     frameState.setNodeSourcePosition(sourcePosition);
 211                     return frameState;
 212                 }
 213             } else {
 214                 // Other non-side-effects do not need a state
 215                 return null;
 216             }
 217         }
 218     }
 219 
 220     @Override
 221     public String toString() {
 222         return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
 223     }
 224 }