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