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     /**
  70      * Gets the method being intrinsified.
  71      */
  72     public ResolvedJavaMethod getOriginalMethod() {
  73         return method;
  74     }
  75 
  76     /**
  77      * Gets the method providing the intrinsic implementation.
  78      */
  79     public ResolvedJavaMethod getIntrinsicMethod() {
  80         return intrinsic;
  81     }
  82 
  83     /**
  84      * Gets provider of bytecode to be parsed for a method that is part of an intrinsic.
  85      */
  86     public BytecodeProvider getBytecodeProvider() {
  87         return bytecodeProvider;
  88     }
  89 
  90     /**
  91      * Determines if a call within the compilation scope of this intrinsic represents a call to the
  92      * {@linkplain #getOriginalMethod() original} method. This denotes the path where a partial
  93      * intrinsification falls back to the original method.
  94      */
  95     public boolean isCallToOriginal(ResolvedJavaMethod targetMethod) {
  96         return method.equals(targetMethod) || intrinsic.equals(targetMethod);
  97     }
  98 
  99     final CompilationContext compilationContext;
 100 
 101     public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
 102         this.method = method;
 103         this.intrinsic = intrinsic;
 104         this.bytecodeProvider = bytecodeProvider;
 105         assert bytecodeProvider != null;
 106         this.compilationContext = compilationContext;
 107         assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
 108     }
 109 
 110     public boolean isPostParseInlined() {
 111         return compilationContext.equals(INLINE_AFTER_PARSING);
 112     }
 113 
 114     public boolean isCompilationRoot() {
 115         return compilationContext.equals(ROOT_COMPILATION);
 116     }
 117 
 118     /**
 119      * Denotes the compilation context in which an intrinsic is being parsed.
 120      */
 121     public enum CompilationContext {
 122         /**
 123          * An intrinsic is being processed when parsing an invoke bytecode that calls the
 124          * intrinsified method.
 125          */
 126         INLINE_DURING_PARSING,
 127 
 128         /**
 129          * An intrinsic is being processed when inlining an {@link Invoke} in an existing graph.
 130          */
 131         INLINE_AFTER_PARSING,
 132 
 133         /**
 134          * An intrinsic is the root of compilation.
 135          */
 136         ROOT_COMPILATION
 137     }
 138 
 139     /**
 140      * Models the state of a graph in terms of {@link StateSplit#hasSideEffect() side effects} that
 141      * are control flow predecessors of the current point in a graph.
 142      */
 143     public interface SideEffectsState {
 144 
 145         /**
 146          * Determines if the current program point is preceded by one or more side effects.
 147          */
 148         boolean isAfterSideEffect();
 149 
 150         /**
 151          * Gets the side effects preceding the current program point.
 152          */
 153         Iterable<StateSplit> sideEffects();
 154 
 155         /**
 156          * Records a side effect for the current program point.
 157          */
 158         void addSideEffect(StateSplit sideEffect);
 159     }
 160 
 161     public FrameState createFrameState(StructuredGraph graph, SideEffectsState sideEffects, StateSplit forStateSplit, NodeSourcePosition sourcePosition) {
 162         assert forStateSplit != graph.start();
 163         if (forStateSplit.hasSideEffect()) {
 164             if (sideEffects.isAfterSideEffect()) {
 165                 // Only the last side effect on any execution path in a replacement
 166                 // can inherit the stateAfter of the replaced node
 167                 FrameState invalid = graph.add(new FrameState(INVALID_FRAMESTATE_BCI));
 168                 invalid.setNodeSourcePosition(sourcePosition);
 169                 for (StateSplit lastSideEffect : sideEffects.sideEffects()) {
 170                     lastSideEffect.setStateAfter(invalid);
 171                 }
 172             }
 173             sideEffects.addSideEffect(forStateSplit);
 174             FrameState frameState;
 175             if (forStateSplit instanceof ExceptionObjectNode) {
 176                 frameState = graph.add(new FrameState(AFTER_EXCEPTION_BCI, (ExceptionObjectNode) forStateSplit));
 177             } else {
 178                 frameState = graph.add(new FrameState(AFTER_BCI));
 179             }
 180             frameState.setNodeSourcePosition(sourcePosition);
 181             return frameState;
 182         } else {
 183             if (forStateSplit instanceof AbstractMergeNode) {
 184                 // Merge nodes always need a frame state
 185                 if (sideEffects.isAfterSideEffect()) {
 186                     // A merge after one or more side effects
 187                     FrameState frameState = graph.add(new FrameState(AFTER_BCI));
 188                     frameState.setNodeSourcePosition(sourcePosition);
 189                     return frameState;
 190                 } else {
 191                     // A merge before any side effects
 192                     FrameState frameState = graph.add(new FrameState(BEFORE_BCI));
 193                     frameState.setNodeSourcePosition(sourcePosition);
 194                     return frameState;
 195                 }
 196             } else {
 197                 // Other non-side-effects do not need a state
 198                 return null;
 199             }
 200         }
 201     }
 202 
 203     @Override
 204     public String toString() {
 205         return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", intrinsic: " + intrinsic.format("%H.%n(%p)") + ", context: " + compilationContext + "}";
 206     }
 207 }