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