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