1 /*
   2  * Copyright (c) 2011, 2019, 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.replacements;
  26 
  27 import org.graalvm.compiler.bytecode.Bytecode;
  28 import org.graalvm.compiler.bytecode.BytecodeProvider;
  29 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.core.common.type.StampFactory;
  32 import org.graalvm.compiler.core.common.type.StampPair;
  33 import org.graalvm.compiler.core.common.type.TypeReference;
  34 import org.graalvm.compiler.debug.DebugCloseable;
  35 import org.graalvm.compiler.debug.DebugContext;
  36 import org.graalvm.compiler.debug.GraalError;
  37 import org.graalvm.compiler.graph.NodeSourcePosition;
  38 import org.graalvm.compiler.nodes.CallTargetNode;
  39 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
  40 import org.graalvm.compiler.nodes.FixedNode;
  41 import org.graalvm.compiler.nodes.FixedWithNextNode;
  42 import org.graalvm.compiler.nodes.FrameState;
  43 import org.graalvm.compiler.nodes.Invoke;
  44 import org.graalvm.compiler.nodes.ParameterNode;
  45 import org.graalvm.compiler.nodes.ReturnNode;
  46 import org.graalvm.compiler.nodes.StateSplit;
  47 import org.graalvm.compiler.nodes.StructuredGraph;
  48 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
  49 import org.graalvm.compiler.nodes.ValueNode;
  50 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  51 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
  52 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  53 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  54 import org.graalvm.compiler.nodes.spi.CoreProviders;
  55 import org.graalvm.compiler.nodes.spi.Replacements;
  56 import org.graalvm.compiler.nodes.spi.StampProvider;
  57 import org.graalvm.compiler.options.OptionValues;
  58 
  59 import jdk.vm.ci.code.BailoutException;
  60 import jdk.vm.ci.code.BytecodeFrame;
  61 import jdk.vm.ci.meta.ConstantReflectionProvider;
  62 import jdk.vm.ci.meta.JavaKind;
  63 import jdk.vm.ci.meta.JavaType;
  64 import jdk.vm.ci.meta.MetaAccessProvider;
  65 import jdk.vm.ci.meta.ResolvedJavaMethod;
  66 import jdk.vm.ci.meta.ResolvedJavaType;
  67 import jdk.vm.ci.meta.Signature;
  68 
  69 /**
  70  * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
  71  * {@link InvocationPlugin} for the method.
  72  */
  73 public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
  74 
  75     protected final CoreProviders providers;
  76     protected final StructuredGraph graph;
  77     protected final Bytecode code;
  78     protected final ResolvedJavaMethod method;
  79     protected final int invokeBci;
  80     protected FixedWithNextNode lastInstr;
  81     protected ValueNode[] arguments;
  82     protected ValueNode returnValue;
  83 
  84     public IntrinsicGraphBuilder(OptionValues options, DebugContext debug, CoreProviders providers, Bytecode code, int invokeBci) {
  85         this(options, debug, providers, code, invokeBci, AllowAssumptions.YES);
  86     }
  87 
  88     protected IntrinsicGraphBuilder(OptionValues options, DebugContext debug, CoreProviders providers, Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
  89         this.providers = providers;
  90         this.code = code;
  91         this.method = code.getMethod();
  92         this.graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).setIsSubstitution(true).trackNodeSourcePosition(true).build();
  93         this.invokeBci = invokeBci;
  94         this.lastInstr = graph.start();
  95 
  96         Signature sig = method.getSignature();
  97         int max = sig.getParameterCount(false);
  98         this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
  99 
 100         int javaIndex = 0;
 101         int index = 0;
 102         if (!method.isStatic()) {
 103             // add the receiver
 104             Stamp receiverStamp = StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(method.getDeclaringClass()));
 105             ValueNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, StampPair.createSingle(receiverStamp)));
 106             arguments[index] = receiver;
 107             javaIndex = 1;
 108             index = 1;
 109         }
 110         ResolvedJavaType accessingClass = method.getDeclaringClass();
 111         for (int i = 0; i < max; i++) {
 112             JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
 113             JavaKind kind = type.getJavaKind();
 114             Stamp stamp;
 115             if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
 116                 stamp = StampFactory.object(TypeReference.createWithoutAssumptions((ResolvedJavaType) type));
 117             } else {
 118                 stamp = StampFactory.forKind(kind);
 119             }
 120             ValueNode param = graph.addWithoutUnique(new ParameterNode(index, StampPair.createSingle(stamp)));
 121             arguments[index] = param;
 122             javaIndex += kind.getSlotCount();
 123             index++;
 124         }
 125     }
 126 
 127     private <T extends ValueNode> void updateLastInstruction(T v) {
 128         if (v instanceof FixedNode) {
 129             FixedNode fixedNode = (FixedNode) v;
 130             if (lastInstr != null) {
 131                 lastInstr.setNext(fixedNode);
 132             }
 133             if (fixedNode instanceof FixedWithNextNode) {
 134                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
 135                 assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
 136                 lastInstr = fixedWithNextNode;
 137             } else {
 138                 lastInstr = null;
 139             }
 140         }
 141     }
 142 
 143     @Override
 144     public <T extends ValueNode> T append(T v) {
 145         if (v.graph() != null) {
 146             return v;
 147         }
 148         T added = graph.addOrUniqueWithInputs(v);
 149         if (added == v) {
 150             updateLastInstruction(v);
 151         }
 152         return added;
 153     }
 154 
 155     @Override
 156     public void push(JavaKind kind, ValueNode value) {
 157         assert kind != JavaKind.Void;
 158         assert returnValue == null;
 159         returnValue = value;
 160     }
 161 
 162     @Override
 163     public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
 164         throw GraalError.shouldNotReachHere();
 165     }
 166 
 167     @Override
 168     public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
 169         throw GraalError.shouldNotReachHere();
 170     }
 171 
 172     @Override
 173     public StampProvider getStampProvider() {
 174         return providers.getStampProvider();
 175     }
 176 
 177     @Override
 178     public MetaAccessProvider getMetaAccess() {
 179         return providers.getMetaAccess();
 180     }
 181 
 182     @Override
 183     public ConstantReflectionProvider getConstantReflection() {
 184         return providers.getConstantReflection();
 185     }
 186 
 187     @Override
 188     public ConstantFieldProvider getConstantFieldProvider() {
 189         return providers.getConstantFieldProvider();
 190     }
 191 
 192     @Override
 193     public Replacements getReplacements() {
 194         return providers.getReplacements();
 195     }
 196 
 197     @Override
 198     public StructuredGraph getGraph() {
 199         return graph;
 200     }
 201 
 202     @Override
 203     public void setStateAfter(StateSplit sideEffect) {
 204         assert sideEffect.hasSideEffect();
 205         FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
 206         sideEffect.setStateAfter(stateAfter);
 207     }
 208 
 209     @Override
 210     public GraphBuilderContext getParent() {
 211         return null;
 212     }
 213 
 214     @Override
 215     public Bytecode getCode() {
 216         return code;
 217     }
 218 
 219     @Override
 220     public ResolvedJavaMethod getMethod() {
 221         return method;
 222     }
 223 
 224     @Override
 225     public int bci() {
 226         return invokeBci;
 227     }
 228 
 229     @Override
 230     public InvokeKind getInvokeKind() {
 231         return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
 232     }
 233 
 234     @Override
 235     public JavaType getInvokeReturnType() {
 236         return method.getSignature().getReturnType(method.getDeclaringClass());
 237     }
 238 
 239     @Override
 240     public int getDepth() {
 241         return 0;
 242     }
 243 
 244     @Override
 245     public boolean parsingIntrinsic() {
 246         return true;
 247     }
 248 
 249     @Override
 250     public IntrinsicContext getIntrinsic() {
 251         throw GraalError.shouldNotReachHere();
 252     }
 253 
 254     @Override
 255     public BailoutException bailout(String string) {
 256         throw GraalError.shouldNotReachHere();
 257     }
 258 
 259     @Override
 260     public ValueNode get(boolean performNullCheck) {
 261         return arguments[0];
 262     }
 263 
 264     @SuppressWarnings("try")
 265     public StructuredGraph buildGraph(InvocationPlugin plugin) {
 266         NodeSourcePosition position = graph.trackNodeSourcePosition() ? NodeSourcePosition.placeholder(method) : null;
 267         try (DebugCloseable context = graph.withNodeSourcePosition(position)) {
 268             Receiver receiver = method.isStatic() ? null : this;
 269             if (plugin.execute(this, method, receiver, arguments)) {
 270                 assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
 271                 append(new ReturnNode(returnValue));
 272                 return graph;
 273             }
 274             return null;
 275         }
 276     }
 277 
 278     @Override
 279     public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
 280         throw GraalError.shouldNotReachHere();
 281     }
 282 
 283     @Override
 284     public boolean intrinsify(ResolvedJavaMethod targetMethod, StructuredGraph substituteGraph, Receiver receiver, ValueNode[] argsIncludingReceiver) {
 285         throw GraalError.shouldNotReachHere();
 286     }
 287 
 288     @Override
 289     public String toString() {
 290         return String.format("%s:intrinsic", method.format("%H.%n(%p)"));
 291     }
 292 }