1 /*
   2  * Copyright (c) 2017, 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.hotspot.meta;
  24 
  25 import org.graalvm.compiler.bytecode.Bytecodes;
  26 import org.graalvm.compiler.core.common.type.Stamp;
  27 import org.graalvm.compiler.debug.GraalError;
  28 import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
  29 import org.graalvm.compiler.nodes.ConstantNode;
  30 import org.graalvm.compiler.nodes.FrameState;
  31 import org.graalvm.compiler.nodes.ValueNode;
  32 import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
  33 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  34 
  35 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  36 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
  37 import jdk.vm.ci.meta.ConstantPool;
  38 import jdk.vm.ci.meta.JavaConstant;
  39 import jdk.vm.ci.meta.ResolvedJavaMethod;
  40 
  41 import java.lang.invoke.MethodHandle;
  42 import java.lang.invoke.MethodHandles;
  43 import java.lang.invoke.MethodType;
  44 
  45 public class HotSpotInvokeDynamicPlugin implements InvokeDynamicPlugin {
  46 
  47     private static final Class<? extends ConstantPool> hscp;
  48     private static final MethodHandle isResolvedDynamicInvokeMH;
  49 
  50     static {
  51         MethodHandle m = null;
  52         Class<? extends ConstantPool> c = null;
  53         try {
  54             c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class);
  55             m = MethodHandles.lookup().findVirtual(c, "isResolvedDynamicInvoke", MethodType.methodType(boolean.class, int.class, int.class));
  56         } catch (Exception e) {
  57         }
  58         isResolvedDynamicInvokeMH = m;
  59         hscp = c;
  60     }
  61 
  62     private static boolean isResolvedDynamicInvoke(ConstantPool constantPool, int index, int opcode) {
  63         if (isResolvedDynamicInvokeMH != null) {
  64             if (!hscp.isInstance(constantPool)) {
  65                 return false;
  66             }
  67             try {
  68                 return (boolean) isResolvedDynamicInvokeMH.invoke(constantPool, index, opcode);
  69             } catch (Throwable t) {
  70                 throw GraalError.shouldNotReachHere(t);
  71             }
  72         }
  73         throw GraalError.shouldNotReachHere("isResolvedDynamicInvokeMH not set");
  74     }
  75 
  76     private final DynamicTypeStore dynoStore;
  77     private final boolean treatAppendixAsConstant;
  78 
  79     public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore, boolean treatAppendixAsConstant) {
  80         this.dynoStore = dynoStore;
  81         this.treatAppendixAsConstant = treatAppendixAsConstant;
  82     }
  83 
  84     public HotSpotInvokeDynamicPlugin(DynamicTypeStore dynoStore) {
  85         this(dynoStore, true);
  86     }
  87 
  88     public HotSpotInvokeDynamicPlugin() {
  89         this(null);
  90     }
  91 
  92     // invokehandle support
  93     @Override
  94     public boolean isResolvedDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
  95         ConstantPool constantPool = builder.getCode().getConstantPool();
  96         if (isResolvedDynamicInvokeMH == null) {
  97             // If older JVMCI, but HotSpotInvokeDynamicPlugin is being
  98             // used for testing, return true so that we continue along the
  99             // plugin path.
 100             return true;
 101         }
 102         return isResolvedDynamicInvoke(constantPool, index, opcode);
 103     }
 104 
 105     @Override
 106     public boolean supportsDynamicInvoke(GraphBuilderContext builder, int index, int opcode) {
 107         return opcode == Bytecodes.INVOKEDYNAMIC || isResolvedDynamicInvokeMH != null;
 108     }
 109 
 110     public DynamicTypeStore getDynamicTypeStore() {
 111         return dynoStore;
 112     }
 113 
 114     @Override
 115     public void recordDynamicMethod(GraphBuilderContext builder, int index, int opcode, ResolvedJavaMethod target) {
 116         assert supportsDynamicInvoke(builder, index, opcode);
 117         HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
 118         HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
 119 
 120         HotSpotResolvedJavaMethod adapter = (HotSpotResolvedJavaMethod) target;
 121         if (dynoStore != null) {
 122             dynoStore.recordAdapter(opcode, methodHolder, index, adapter);
 123         }
 124     }
 125 
 126     @Override
 127     public ValueNode genAppendixNode(GraphBuilderContext builder, int index, int opcode, JavaConstant appendixConstant, FrameState frameState) {
 128         JavaConstant appendix = appendixConstant;
 129         assert supportsDynamicInvoke(builder, index, opcode);
 130         HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) builder.getMethod();
 131         HotSpotResolvedObjectType methodHolder = method.getDeclaringClass();
 132 
 133         if (dynoStore != null) {
 134             appendix = dynoStore.recordAppendix(opcode, methodHolder, index, appendix);
 135         }
 136 
 137         ConstantNode appendixNode = ConstantNode.forConstant(appendix, builder.getMetaAccess(), builder.getGraph());
 138 
 139         Stamp appendixStamp = appendixNode.stamp();
 140         Stamp resolveStamp = treatAppendixAsConstant ? appendixStamp : appendixStamp.unrestricted();
 141         ResolveDynamicConstantNode resolveNode = new ResolveDynamicConstantNode(resolveStamp, appendixNode);
 142         ResolveDynamicConstantNode added = builder.append(resolveNode);
 143         assert added == resolveNode;
 144         added.setStateBefore(frameState);
 145         return resolveNode;
 146     }
 147 
 148     public interface DynamicTypeStore {
 149 
 150         void recordAdapter(int opcode, HotSpotResolvedObjectType holder, int cpi, HotSpotResolvedJavaMethod adapter);
 151 
 152         JavaConstant recordAppendix(int opcode, HotSpotResolvedObjectType holder, int cpi, JavaConstant appendix);
 153 
 154     }
 155 
 156 }