001/* 002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.graphbuilderconf; 024 025import jdk.internal.jvmci.code.*; 026import jdk.internal.jvmci.meta.*; 027import static com.oracle.graal.compiler.common.type.StampFactory.*; 028import static jdk.internal.jvmci.meta.DeoptimizationAction.*; 029import static jdk.internal.jvmci.meta.DeoptimizationReason.*; 030 031import com.oracle.graal.compiler.common.type.*; 032import com.oracle.graal.nodes.CallTargetNode.InvokeKind; 033import com.oracle.graal.nodes.*; 034import com.oracle.graal.nodes.calc.*; 035import com.oracle.graal.nodes.spi.*; 036import com.oracle.graal.nodes.type.*; 037 038/** 039 * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a 040 * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} . 041 */ 042public interface GraphBuilderContext { 043 044 /** 045 * Raw operation for adding a node to the graph when neither {@link #add} nor 046 * {@link #addPush(Kind, ValueNode)} can be used. 047 * 048 * @return either the node added or an equivalent node 049 */ 050 <T extends ValueNode> T append(T value); 051 052 /** 053 * Adds the given node to the graph and also adds recursively all referenced inputs. 054 * 055 * @param value the node to be added to the graph 056 * @return either the node added or an equivalent node 057 */ 058 <T extends ValueNode> T recursiveAppend(T value); 059 060 /** 061 * Pushes a given value to the frame state stack using an explicit kind. This should be used 062 * when {@code value.getKind()} is different from the kind that the bytecode instruction 063 * currently being parsed pushes to the stack. 064 * 065 * @param kind the kind to use when type checking this operation 066 * @param value the value to push to the stack. The value must already have been 067 * {@linkplain #append(ValueNode) appended}. 068 */ 069 void push(Kind kind, ValueNode value); 070 071 /** 072 * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null 073 * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized. 074 * 075 * @param value the value to add to the graph and push to the stack. The {@code value.getKind()} 076 * kind is used when type checking this operation. 077 * @return a node equivalent to {@code value} in the graph 078 */ 079 default <T extends ValueNode> T add(T value) { 080 if (value.graph() != null) { 081 assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null; 082 return value; 083 } 084 T equivalentValue = append(value); 085 if (equivalentValue instanceof StateSplit) { 086 StateSplit stateSplit = (StateSplit) equivalentValue; 087 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { 088 setStateAfter(stateSplit); 089 } 090 } 091 return equivalentValue; 092 } 093 094 /** 095 * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node 096 * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the 097 * frame state is initialized. 098 * 099 * @param kind the kind to use when type checking this operation 100 * @param value the value to add to the graph and push to the stack 101 * @return a node equivalent to {@code value} in the graph 102 */ 103 default <T extends ValueNode> T addPush(Kind kind, T value) { 104 T equivalentValue = value.graph() != null ? value : append(value); 105 push(kind, equivalentValue); 106 if (equivalentValue instanceof StateSplit) { 107 StateSplit stateSplit = (StateSplit) equivalentValue; 108 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { 109 setStateAfter(stateSplit); 110 } 111 } 112 return equivalentValue; 113 } 114 115 /** 116 * Handles an invocation that a plugin determines can replace the original invocation (i.e., the 117 * one for which the plugin was applied). This applies all standard graph builder processing to 118 * the replaced invocation including applying any relevant plugins. 119 * 120 * @param invokeKind the kind of the replacement invocation 121 * @param targetMethod the target of the replacement invocation 122 * @param args the arguments to the replacement invocation 123 * @param forceInlineEverything specifies if all invocations encountered in the scope of 124 * handling the replaced invoke are to be force inlined 125 */ 126 void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything); 127 128 /** 129 * Intrinsifies an invocation of a given method by inlining the bytecodes of a given 130 * substitution method. 131 * 132 * @param targetMethod the method being intrinsified 133 * @param substitute the intrinsic implementation 134 * @param args the arguments with which to inline the invocation 135 */ 136 void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args); 137 138 StampProvider getStampProvider(); 139 140 MetaAccessProvider getMetaAccess(); 141 142 default Assumptions getAssumptions() { 143 return getGraph().getAssumptions(); 144 } 145 146 ConstantReflectionProvider getConstantReflection(); 147 148 /** 149 * Gets the graph being constructed. 150 */ 151 StructuredGraph getGraph(); 152 153 /** 154 * Creates a snap shot of the current frame state with the BCI of the instruction after the one 155 * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side 156 * effect} node. 157 * 158 * @param sideEffect a side effect node just appended to the graph 159 */ 160 void setStateAfter(StateSplit sideEffect); 161 162 /** 163 * Gets the parsing context for the method that inlines the method being parsed by this context. 164 */ 165 GraphBuilderContext getParent(); 166 167 /** 168 * Gets the first ancestor parsing context that is not parsing a 169 * {@linkplain #parsingIntrinsic() intrinsic}. 170 */ 171 default GraphBuilderContext getNonIntrinsicAncestor() { 172 GraphBuilderContext ancestor = getParent(); 173 while (ancestor != null && ancestor.parsingIntrinsic()) { 174 ancestor = ancestor.getParent(); 175 } 176 return ancestor; 177 } 178 179 /** 180 * Gets the method being parsed by this context. 181 */ 182 ResolvedJavaMethod getMethod(); 183 184 /** 185 * Gets the index of the bytecode instruction currently being parsed. 186 */ 187 int bci(); 188 189 /** 190 * Gets the kind of invocation currently being parsed. 191 */ 192 InvokeKind getInvokeKind(); 193 194 /** 195 * Gets the return type of the invocation currently being parsed. 196 */ 197 JavaType getInvokeReturnType(); 198 199 default Stamp getInvokeReturnStamp() { 200 JavaType returnType = getInvokeReturnType(); 201 if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) { 202 return StampFactory.declared((ResolvedJavaType) returnType); 203 } else { 204 return StampFactory.forKind(returnType.getKind()); 205 } 206 } 207 208 /** 209 * Gets the inline depth of this context. A return value of 0 implies that this is the context 210 * for the parse root. 211 */ 212 default int getDepth() { 213 GraphBuilderContext parent = getParent(); 214 return parent == null ? 0 : 1 + parent.getDepth(); 215 } 216 217 /** 218 * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined 219 * by an intrinsic. 220 */ 221 default boolean parsingIntrinsic() { 222 return getIntrinsic() != null; 223 } 224 225 /** 226 * Gets the intrinsic of the current parsing context or {@code null} if not 227 * {@link #parsingIntrinsic() parsing an intrinsic}. 228 */ 229 IntrinsicContext getIntrinsic(); 230 231 BailoutException bailout(String string); 232 233 /** 234 * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode) 235 * non-null} stamp. 236 */ 237 default ValueNode nullCheckedValue(ValueNode value) { 238 if (!StampTool.isPointerNonNull(value.stamp())) { 239 IsNullNode condition = getGraph().unique(new IsNullNode(value)); 240 ObjectStamp receiverStamp = (ObjectStamp) value.stamp(); 241 Stamp stamp = receiverStamp.join(objectNonNull()); 242 FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true)); 243 PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp)); 244 nonNullReceiver.setGuard(fixedGuard); 245 // TODO: Propogating the non-null into the frame state would 246 // remove subsequent null-checks on the same value. However, 247 // it currently causes an assertion failure when merging states. 248 // 249 // frameState.replace(value, nonNullReceiver); 250 return nonNullReceiver; 251 } 252 return value; 253 } 254}