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 }