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