1 /*
   2  * Copyright (c) 2015, 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.hotspot.meta;
  24 
  25 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateRecompile;
  26 import static jdk.vm.ci.meta.DeoptimizationReason.Unresolved;
  27 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  28 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
  29 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
  30 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
  31 import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
  32 
  33 import java.lang.invoke.ConstantCallSite;
  34 import java.lang.invoke.MutableCallSite;
  35 import java.lang.invoke.VolatileCallSite;
  36 import java.lang.reflect.Method;
  37 import java.lang.reflect.Modifier;
  38 import java.math.BigInteger;
  39 import java.util.zip.CRC32;
  40 
  41 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  42 import org.graalvm.compiler.bytecode.BytecodeProvider;
  43 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  44 import org.graalvm.compiler.debug.GraalError;
  45 import org.graalvm.compiler.hotspot.FingerprintUtil;
  46 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  47 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
  48 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
  49 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
  50 import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
  51 import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
  52 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
  53 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
  54 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  55 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
  56 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
  57 import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions;
  58 import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
  59 import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
  60 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
  61 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
  62 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
  63 import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions;
  64 import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
  65 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
  66 import org.graalvm.compiler.nodes.ConstantNode;
  67 import org.graalvm.compiler.nodes.DeoptimizeNode;
  68 import org.graalvm.compiler.nodes.DynamicPiNode;
  69 import org.graalvm.compiler.nodes.FixedGuardNode;
  70 import org.graalvm.compiler.nodes.LogicNode;
  71 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  72 import org.graalvm.compiler.nodes.PiNode;
  73 import org.graalvm.compiler.nodes.ValueNode;
  74 import org.graalvm.compiler.nodes.calc.AddNode;
  75 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  76 import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
  77 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  78 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  79 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  80 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  81 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  82 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  83 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
  85 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
  86 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
  87 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  88 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  89 import org.graalvm.compiler.nodes.spi.StampProvider;
  90 import org.graalvm.compiler.nodes.util.GraphUtil;
  91 import org.graalvm.compiler.options.OptionValues;
  92 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
  93 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
  94 import org.graalvm.compiler.replacements.MethodHandlePlugin;
  95 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
  96 import org.graalvm.compiler.replacements.ReplacementsImpl;
  97 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
  98 import org.graalvm.compiler.serviceprovider.GraalServices;
  99 import org.graalvm.compiler.serviceprovider.JDK9Method;
 100 import org.graalvm.compiler.word.WordOperationPlugin;
 101 import org.graalvm.compiler.word.WordTypes;
 102 import org.graalvm.word.LocationIdentity;
 103 
 104 import jdk.vm.ci.code.CodeUtil;
 105 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 106 import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
 107 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 108 import jdk.vm.ci.meta.ConstantReflectionProvider;
 109 import jdk.vm.ci.meta.DeoptimizationAction;
 110 import jdk.vm.ci.meta.DeoptimizationReason;
 111 import jdk.vm.ci.meta.JavaConstant;
 112 import jdk.vm.ci.meta.JavaKind;
 113 import jdk.vm.ci.meta.MetaAccessProvider;
 114 import jdk.vm.ci.meta.ResolvedJavaMethod;
 115 
 116 /**
 117  * Defines the {@link Plugins} used when running on HotSpot.
 118  */
 119 public class HotSpotGraphBuilderPlugins {
 120 
 121     /**
 122      * Creates a {@link Plugins} object that should be used when running on HotSpot.
 123      *
 124      * @param constantReflection
 125      * @param snippetReflection
 126      * @param foreignCalls
 127      * @param stampProvider
 128      */
 129     public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess,
 130                     ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider,
 131                     ReplacementsImpl replacements) {
 132         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration);
 133 
 134         Plugins plugins = new Plugins(invocationPlugins);
 135         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
 136         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 137         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin);
 138 
 139         plugins.appendTypePlugin(nodePlugin);
 140         plugins.appendNodePlugin(nodePlugin);
 141         OptionValues options = replacements.getOptions();
 142         if (GeneratePIC.getValue(options)) {
 143             // AOT needs to filter out bad invokes
 144             plugins.prependNodePlugin(new NodePlugin() {
 145                 @Override
 146                 public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
 147                     if (b.parsingIntrinsic()) {
 148                         return false;
 149                     }
 150                     // check if the holder has a valid fingerprint
 151                     if (FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) method.getDeclaringClass()) == 0) {
 152                         // Deopt otherwise
 153                         b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
 154                         return true;
 155                     }
 156                     // the last argument that may come from appendix, check if it is a supported
 157                     // constant type
 158                     if (args.length > 0) {
 159                         JavaConstant constant = args[args.length - 1].asJavaConstant();
 160                         if (constant != null && constant instanceof HotSpotObjectConstant) {
 161                             HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) ((HotSpotObjectConstant) constant).getType();
 162                             Class<?> clazz = type.mirror();
 163                             if (clazz.equals(String.class)) {
 164                                 return false;
 165                             }
 166                             if (Class.class.isAssignableFrom(clazz) && FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) != 0) {
 167                                 return false;
 168                             }
 169                             b.append(new DeoptimizeNode(InvalidateRecompile, Unresolved));
 170                             return true;
 171                         }
 172                     }
 173                     return false;
 174                 }
 175             });
 176         }
 177         plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
 178         plugins.appendInlineInvokePlugin(replacements);
 179         if (InlineDuringParsing.getValue(options)) {
 180             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
 181         }
 182 
 183         if (GeneratePIC.getValue(options)) {
 184             plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
 185             if (TieredAOT.getValue(options)) {
 186                 plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
 187             }
 188         }
 189 
 190         invocationPlugins.defer(new Runnable() {
 191 
 192             @Override
 193             public void run() {
 194                 BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
 195                 registerObjectPlugins(invocationPlugins, options, replacementBytecodeProvider);
 196                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
 197                 registerSystemPlugins(invocationPlugins, foreignCalls);
 198                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
 199                 registerCallSitePlugins(invocationPlugins);
 200                 registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
 201                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
 202                 registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
 203                 registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
 204                 registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
 205                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
 206                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
 207 
 208                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
 209                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
 210                 }
 211             }
 212         });
 213         return plugins;
 214     }
 215 
 216     private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, BytecodeProvider bytecodeProvider) {
 217         Registration r = new Registration(plugins, Object.class, bytecodeProvider);
 218         if (!GeneratePIC.getValue(options)) {
 219             // FIXME: clone() requires speculation and requires a fix in here (to check that
 220             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
 221             // an instantiation of IntrinsicGraphBuilder using a constructor that sets
 222             // AllowAssumptions to YES automatically. The former has to inherit the assumptions
 223             // settings from the root compile instead. So, for now, I'm disabling it for
 224             // GeneratePIC.
 225             r.register1("clone", Receiver.class, new InvocationPlugin() {
 226                 @Override
 227                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 228                     ValueNode object = receiver.get();
 229                     b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
 230                     return true;
 231                 }
 232 
 233                 @Override
 234                 public boolean inlineOnly() {
 235                     return true;
 236                 }
 237             });
 238         }
 239         r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
 240     }
 241 
 242     private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 243         Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
 244 
 245         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
 246         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
 247         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
 248         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
 249         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
 250 
 251         if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
 252             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
 253         }
 254 
 255         r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
 256             @Override
 257             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 258                 ValueNode javaClass = receiver.get();
 259                 LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), javaClass, object, true));
 260                 if (condition.isTautology()) {
 261                     b.addPush(JavaKind.Object, object);
 262                 } else {
 263                     FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
 264                     b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass));
 265                 }
 266                 return true;
 267             }
 268 
 269             @Override
 270             public boolean inlineOnly() {
 271                 return true;
 272             }
 273         });
 274     }
 275 
 276     private static void registerCallSitePlugins(InvocationPlugins plugins) {
 277         InvocationPlugin plugin = new InvocationPlugin() {
 278             @Override
 279             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 280                 ValueNode callSite = receiver.get();
 281                 ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
 282                 if (folded != null) {
 283                     b.addPush(JavaKind.Object, folded);
 284                 } else {
 285                     b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
 286                 }
 287                 return true;
 288             }
 289 
 290             @Override
 291             public boolean inlineOnly() {
 292                 return true;
 293             }
 294         };
 295         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
 296         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
 297         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
 298     }
 299 
 300     private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 301         Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
 302         r.register0("getCallerClass", new InvocationPlugin() {
 303             @Override
 304             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 305                 b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
 306                 return true;
 307             }
 308 
 309             @Override
 310             public boolean inlineOnly() {
 311                 return true;
 312             }
 313         });
 314         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
 315     }
 316 
 317     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
 318     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 319 
 320     /**
 321      * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
 322      * {@code constantPoolOop} field in a ConstantPool value.
 323      *
 324      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 325      * @return a node representing the metaspace {@code ConstantPool} pointer associated with
 326      *         {@code constantPoolOop}
 327      */
 328     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 329         // ConstantPool.constantPoolOop is in fact the holder class.
 330         ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
 331         ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 332 
 333         boolean notCompressible = false;
 334         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
 335         return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
 336     }
 337 
 338     /**
 339      * Emits a node representing an element in a metaspace {@code ConstantPool}.
 340      *
 341      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 342      */
 343     private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 344         ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 345         int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
 346         ValueNode scaledIndex = b.add(new LeftShiftNode(index, b.add(ConstantNode.forInt(shift))));
 347         ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forInt(config.constantPoolSize))));
 348         AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
 349         boolean notCompressible = false;
 350         ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
 351         b.addPush(elementKind, elementValue);
 352         return true;
 353     }
 354 
 355     private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 356         Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
 357 
 358         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
 359             @Override
 360             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
 361                 boolean notCompressible = false;
 362                 ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 363                 AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
 364                 ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
 365                 b.addPush(JavaKind.Int, length);
 366                 return true;
 367             }
 368         });
 369 
 370         r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 371             @Override
 372             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 373                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
 374             }
 375         });
 376         r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 377             @Override
 378             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 379                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
 380             }
 381         });
 382         r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 383             @Override
 384             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 385                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
 386             }
 387         });
 388         r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 389             @Override
 390             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 391                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
 392             }
 393         });
 394     }
 395 
 396     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
 397         Registration r = new Registration(plugins, System.class);
 398         r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
 399         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
 400         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
 401             @Override
 402             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 403                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 404                 return true;
 405             }
 406 
 407             @Override
 408             public boolean inlineOnly() {
 409                 return true;
 410             }
 411         });
 412         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
 413             @Override
 414             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
 415                 b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
 416                 return true;
 417             }
 418 
 419             @Override
 420             public boolean inlineOnly() {
 421                 return true;
 422             }
 423         });
 424     }
 425 
 426     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 427         Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
 428         r.register0("currentThread", new InvocationPlugin() {
 429             @Override
 430             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 431                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
 432                 boolean compressible = false;
 433                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
 434                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
 435                 ValueNode javaThread = WordOperationPlugin.readOp(b, JavaKind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible);
 436                 boolean exactType = false;
 437                 boolean nonNull = true;
 438                 b.addPush(JavaKind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull));
 439                 return true;
 440             }
 441         });
 442 
 443         r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
 444     }
 445 
 446     public static final String cbcEncryptName;
 447     public static final String cbcDecryptName;
 448     public static final String aesEncryptName;
 449     public static final String aesDecryptName;
 450 
 451     public static final String reflectionClass;
 452     public static final String constantPoolClass;
 453 
 454     static {
 455         if (JDK9Method.Java8OrEarlier) {
 456             cbcEncryptName = "encrypt";
 457             cbcDecryptName = "decrypt";
 458             aesEncryptName = "encryptBlock";
 459             aesDecryptName = "decryptBlock";
 460             reflectionClass = "sun.reflect.Reflection";
 461             constantPoolClass = "sun.reflect.ConstantPool";
 462         } else {
 463             cbcEncryptName = "implEncrypt";
 464             cbcDecryptName = "implDecrypt";
 465             aesEncryptName = "implEncryptBlock";
 466             aesDecryptName = "implDecryptBlock";
 467             reflectionClass = "jdk.internal.reflect.Reflection";
 468             constantPoolClass = "jdk.internal.reflect.ConstantPool";
 469         }
 470     }
 471 
 472     private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 473         if (config.useAESIntrinsics) {
 474             assert config.aescryptEncryptBlockStub != 0L;
 475             assert config.aescryptDecryptBlockStub != 0L;
 476             assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
 477             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
 478             String arch = config.osArch;
 479             String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
 480             Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
 481             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
 482             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
 483                             int.class);
 484             r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
 485             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 486             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 487         }
 488     }
 489 
 490     private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 491         Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
 492         if (config.useMultiplyToLenIntrinsic()) {
 493             assert config.multiplyToLen != 0L;
 494             if (Java8OrEarlier) {
 495                 try {
 496                     Method m = BigInteger.class.getDeclaredMethod("multiplyToLen", int[].class, int.class, int[].class, int.class, int[].class);
 497                     if (Modifier.isStatic(m.getModifiers())) {
 498                         r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
 499                                         int[].class);
 500                     } else {
 501                         r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", Receiver.class, int[].class, int.class, int[].class, int.class,
 502                                         int[].class);
 503                     }
 504                 } catch (NoSuchMethodException | SecurityException e) {
 505                     throw new GraalError(e);
 506                 }
 507             } else {
 508                 r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
 509                                 int[].class);
 510             }
 511         }
 512         if (config.useMulAddIntrinsic()) {
 513             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
 514         }
 515         if (config.useMontgomeryMultiplyIntrinsic()) {
 516             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class);
 517         }
 518         if (config.useMontgomerySquareIntrinsic()) {
 519             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class);
 520         }
 521         if (config.useSquareToLenIntrinsic()) {
 522             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
 523         }
 524     }
 525 
 526     private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 527         if (config.useSHA1Intrinsics()) {
 528             assert config.sha1ImplCompress != 0L;
 529             Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider);
 530             r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 531         }
 532         if (config.useSHA256Intrinsics()) {
 533             assert config.sha256ImplCompress != 0L;
 534             Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider);
 535             r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 536         }
 537         if (config.useSHA512Intrinsics()) {
 538             assert config.sha512ImplCompress != 0L;
 539             Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider);
 540             r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 541         }
 542     }
 543 
 544     private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 545         if (config.useCRC32Intrinsics) {
 546             Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
 547             r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
 548             if (Java8OrEarlier) {
 549                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 550                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
 551             } else {
 552                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
 553                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
 554             }
 555         }
 556     }
 557 }