1 /*
   2  * Copyright (c) 2015, 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.hotspot.meta;
  26 
  27 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  28 import static org.graalvm.compiler.hotspot.HotSpotBackend.BASE64_ENCODE_BLOCK;
  29 import static org.graalvm.compiler.hotspot.HotSpotBackend.GHASH_PROCESS_BLOCKS;
  30 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
  31 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
  32 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
  33 
  34 import java.lang.invoke.ConstantCallSite;
  35 import java.lang.invoke.MutableCallSite;
  36 import java.lang.invoke.VolatileCallSite;
  37 import java.lang.reflect.Array;
  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.core.common.type.ObjectStamp;
  45 import org.graalvm.compiler.core.common.type.StampFactory;
  46 import org.graalvm.compiler.core.common.type.TypeReference;
  47 import org.graalvm.compiler.debug.GraalError;
  48 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  49 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
  50 import org.graalvm.compiler.hotspot.replacements.ContinuationSubstitutions;
  51 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
  52 import org.graalvm.compiler.hotspot.replacements.ArraysSupportSubstitutions;
  53 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
  54 import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions;
  55 import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
  56 import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
  57 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
  58 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
  59 import org.graalvm.compiler.hotspot.replacements.CounterModeSubstitutions;
  60 import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions;
  61 import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions;
  62 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  63 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
  64 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
  65 import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions;
  66 import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
  67 import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
  68 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
  69 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
  70 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
  71 import org.graalvm.compiler.hotspot.replacements.StringUTF16Substitutions;
  72 import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions;
  73 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
  74 import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
  75 import org.graalvm.compiler.nodes.ConstantNode;
  76 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  77 import org.graalvm.compiler.nodes.NodeView;
  78 import org.graalvm.compiler.nodes.ValueNode;
  79 import org.graalvm.compiler.nodes.calc.AddNode;
  80 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  81 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  82 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  83 import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  85 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  86 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  87 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  88 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  89 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  90 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
  91 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
  92 import org.graalvm.compiler.nodes.memory.ReadNode;
  93 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  94 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  95 import org.graalvm.compiler.nodes.util.GraphUtil;
  96 import org.graalvm.compiler.options.OptionValues;
  97 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
  98 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
  99 import org.graalvm.compiler.replacements.MethodHandlePlugin;
 100 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
 101 import org.graalvm.compiler.replacements.ReplacementsImpl;
 102 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
 103 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode;
 104 import org.graalvm.compiler.serviceprovider.GraalServices;
 105 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 106 import org.graalvm.compiler.word.WordOperationPlugin;
 107 import org.graalvm.compiler.word.WordTypes;
 108 import jdk.internal.vm.compiler.word.LocationIdentity;
 109 
 110 import jdk.vm.ci.code.CodeUtil;
 111 import jdk.vm.ci.hotspot.VMIntrinsicMethod;
 112 import jdk.vm.ci.meta.ConstantReflectionProvider;
 113 import jdk.vm.ci.meta.DeoptimizationAction;
 114 import jdk.vm.ci.meta.JavaKind;
 115 import jdk.vm.ci.meta.MetaAccessProvider;
 116 import jdk.vm.ci.meta.ResolvedJavaMethod;
 117 import sun.misc.Unsafe;
 118 
 119 /**
 120  * Defines the {@link Plugins} used when running on HotSpot.
 121  */
 122 public class HotSpotGraphBuilderPlugins {
 123 
 124     /**
 125      * Creates a {@link Plugins} object that should be used when running on HotSpot.
 126      *
 127      * @param constantReflection
 128      * @param snippetReflection
 129      * @param foreignCalls
 130      * @param options
 131      */
 132     public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess,
 133                     ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ReplacementsImpl replacements,
 134                     OptionValues options) {
 135         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration);
 136 
 137         Plugins plugins = new Plugins(invocationPlugins);
 138         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
 139         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 140         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, config, wordTypes);
 141 
 142         plugins.appendTypePlugin(nodePlugin);
 143         plugins.appendNodePlugin(nodePlugin);
 144         if (!GeneratePIC.getValue(options)) {
 145             plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
 146         }
 147         plugins.appendInlineInvokePlugin(replacements);
 148         if (InlineDuringParsing.getValue(options)) {
 149             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
 150         }
 151         registerContinuationPlugins(invocationPlugins, foreignCalls, replacements.getDefaultReplacementBytecodeProvider());
 152         if (GeneratePIC.getValue(options)) {
 153             plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
 154             if (TieredAOT.getValue(options)) {
 155                 plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
 156             }
 157         }
 158 
 159         invocationPlugins.defer(new Runnable() {
 160 
 161             @Override
 162             public void run() {
 163                 BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
 164                 registerObjectPlugins(invocationPlugins, options, config, replacementBytecodeProvider);
 165                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
 166                 registerSystemPlugins(invocationPlugins, foreignCalls);
 167                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
 168                 if (!GeneratePIC.getValue(options)) {
 169                     registerCallSitePlugins(invocationPlugins);
 170                 }
 171                 registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
 172                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
 173                 registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
 174                 registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
 175                 registerCRC32CPlugins(invocationPlugins, config, replacementBytecodeProvider);
 176                 registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
 177                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
 178                 registerGHASHPlugins(invocationPlugins, config, metaAccess, foreignCalls);
 179                 registerCounterModePlugins(invocationPlugins, config, replacementBytecodeProvider);
 180                 registerBase64Plugins(invocationPlugins, config, metaAccess, foreignCalls);
 181                 registerUnsafePlugins(invocationPlugins, config, replacementBytecodeProvider);
 182                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true, false);
 183                 registerArrayPlugins(invocationPlugins, replacementBytecodeProvider);
 184                 registerStringPlugins(invocationPlugins, replacementBytecodeProvider);
 185                 registerArraysSupportPlugins(invocationPlugins, config, replacementBytecodeProvider);
 186 
 187                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
 188                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
 189                 }
 190             }
 191         });
 192         return plugins;
 193     }
 194 
 195     private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 196         Registration r = new Registration(plugins, Object.class, bytecodeProvider);
 197         if (!GeneratePIC.getValue(options)) {
 198             // FIXME: clone() requires speculation and requires a fix in here (to check that
 199             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
 200             // an instantiation of IntrinsicGraphBuilder using a constructor that sets
 201             // AllowAssumptions to YES automatically. The former has to inherit the assumptions
 202             // settings from the root compile instead. So, for now, I'm disabling it for
 203             // GeneratePIC.
 204             r.register1("clone", Receiver.class, new InvocationPlugin() {
 205                 @Override
 206                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 207                     ValueNode object = receiver.get();
 208                     b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
 209                     return true;
 210                 }
 211 
 212                 @Override
 213                 public boolean inlineOnly() {
 214                     return true;
 215                 }
 216             });
 217         }
 218         r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
 219         if (config.inlineNotify()) {
 220             r.registerMethodSubstitution(ObjectSubstitutions.class, "notify", Receiver.class);
 221         }
 222         if (config.inlineNotifyAll()) {
 223             r.registerMethodSubstitution(ObjectSubstitutions.class, "notifyAll", Receiver.class);
 224         }
 225     }
 226 
 227     private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 228         Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
 229 
 230         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
 231         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
 232         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
 233         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
 234         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
 235 
 236         if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
 237             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
 238         }
 239     }
 240 
 241     private static void registerCallSitePlugins(InvocationPlugins plugins) {
 242         InvocationPlugin plugin = new InvocationPlugin() {
 243             @Override
 244             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 245                 ValueNode callSite = receiver.get();
 246                 ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
 247                 if (folded != null) {
 248                     b.addPush(JavaKind.Object, folded);
 249                 } else {
 250                     b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
 251                 }
 252                 return true;
 253             }
 254 
 255             @Override
 256             public boolean inlineOnly() {
 257                 return true;
 258             }
 259         };
 260         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
 261         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
 262         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
 263     }
 264 
 265     private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 266         Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
 267         r.register0("getCallerClass", new InvocationPlugin() {
 268             @Override
 269             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 270                 b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
 271                 return true;
 272             }
 273 
 274             @Override
 275             public boolean inlineOnly() {
 276                 return true;
 277             }
 278         });
 279         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
 280     }
 281 
 282     private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider replacementBytecodeProvider) {
 283         Registration r;
 284         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 285             r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
 286         } else {
 287             r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
 288         }
 289         String substituteMethodName = config.doingUnsafeAccessOffset != Integer.MAX_VALUE ? "copyMemoryGuarded" : "copyMemory";
 290         r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, substituteMethodName, Receiver.class, Object.class, long.class, Object.class,
 291                         long.class, long.class);
 292     }
 293 
 294     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
 295     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 296 
 297     /**
 298      * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
 299      * {@code constantPoolOop} field in a ConstantPool value.
 300      *
 301      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 302      * @return a node representing the metaspace {@code ConstantPool} pointer associated with
 303      *         {@code constantPoolOop}
 304      */
 305     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 306         // ConstantPool.constantPoolOop is in fact the holder class.
 307         ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
 308         ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 309 
 310         boolean notCompressible = false;
 311         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
 312         return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
 313     }
 314 
 315     /**
 316      * Emits a node representing an element in a metaspace {@code ConstantPool}.
 317      *
 318      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 319      */
 320     private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 321         ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 322         int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
 323         ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long), NodeView.DEFAULT), b.add(ConstantNode.forInt(shift))));
 324         ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
 325         AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
 326         boolean notCompressible = false;
 327         ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
 328         b.addPush(elementKind, elementValue);
 329         return true;
 330     }
 331 
 332     private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 333         Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
 334 
 335         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
 336             @Override
 337             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
 338                 boolean notCompressible = false;
 339                 ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 340                 AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
 341                 ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
 342                 b.addPush(JavaKind.Int, length);
 343                 return true;
 344             }
 345         });
 346 
 347         r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 348             @Override
 349             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 350                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
 351             }
 352         });
 353         r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 354             @Override
 355             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 356                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
 357             }
 358         });
 359         r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 360             @Override
 361             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 362                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
 363             }
 364         });
 365         r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 366             @Override
 367             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 368                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
 369             }
 370         });
 371     }
 372 
 373     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
 374         Registration r = new Registration(plugins, System.class);
 375         r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
 376         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
 377         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
 378             @Override
 379             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 380                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 381                 return true;
 382             }
 383 
 384             @Override
 385             public boolean inlineOnly() {
 386                 return true;
 387             }
 388         });
 389         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
 390             @Override
 391             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
 392                 b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
 393                 return true;
 394             }
 395 
 396             @Override
 397             public boolean inlineOnly() {
 398                 return true;
 399             }
 400         });
 401     }
 402 
 403     private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 404         Registration r = new Registration(plugins, Array.class, bytecodeProvider);
 405         r.setAllowOverwrite(true);
 406         r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
 407     }
 408 
 409     private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 410         if (JavaVersionUtil.JAVA_SPEC > 8) {
 411             final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
 412             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "toBytes", char[].class, int.class, int.class);
 413             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
 414         }
 415     }
 416 
 417     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 418         Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
 419         r.register0("currentThread0", new InvocationPlugin() {
 420             @Override
 421             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 422                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
 423                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
 424                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
 425                 // JavaThread::_threadObj is never compressed
 426                 ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
 427                 b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
 428                 return true;
 429             }
 430         });
 431 
 432         r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
 433     }
 434 
 435     private static void registerContinuationPlugins(InvocationPlugins plugins,  ForeignCallsProvider foreignCalls, BytecodeProvider bytecodeProvider) {
 436         Registration r1 = new Registration(plugins, Continuation.class, bytecodeProvider);
 437         r1.registerMethodSubstitution(ContinuationSubstitutions.class, "getSP");
 438         r1.register1("doContinue", Receiver.class, new ForeignCallPlugin(foreignCalls, ContinuationSubstitutions.CONTINUATION_DO_CONTINUE));
 439         r1.register1("doYield", int.class, new ForeignCallPlugin(foreignCalls, ContinuationSubstitutions.CONTINUATION_YIELD));
 440         r1.registerMethodSubstitution(ContinuationSubstitutions.class, "runLevel");
 441     }
 442 
 443     public static final String aesEncryptName;
 444     public static final String aesDecryptName;
 445 
 446     public static final String reflectionClass;
 447     public static final String constantPoolClass;
 448 
 449     static {
 450         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 451             aesEncryptName = "encryptBlock";
 452             aesDecryptName = "decryptBlock";
 453             reflectionClass = "sun.reflect.Reflection";
 454             constantPoolClass = "sun.reflect.ConstantPool";
 455         } else {
 456             aesEncryptName = "implEncryptBlock";
 457             aesDecryptName = "implDecryptBlock";
 458             reflectionClass = "jdk.internal.reflect.Reflection";
 459             constantPoolClass = "jdk.internal.reflect.ConstantPool";
 460         }
 461     }
 462 
 463     public static boolean cbcUsesImplNames(GraalHotSpotVMConfig config) {
 464         for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
 465             if ("com/sun/crypto/provider/CipherBlockChaining".equals(intrinsic.declaringClass)) {
 466                 if ("encrypt".equals(intrinsic.name)) {
 467                     return false;
 468                 } else if ("implEncrypt".equals(intrinsic.name)) {
 469                     return true;
 470                 }
 471             }
 472         }
 473         throw GraalError.shouldNotReachHere();
 474     }
 475 
 476     private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 477         if (config.useAESIntrinsics) {
 478             assert config.aescryptEncryptBlockStub != 0L;
 479             assert config.aescryptDecryptBlockStub != 0L;
 480             assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
 481             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
 482             String arch = config.osArch;
 483             String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
 484             Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
 485 
 486             boolean implNames = cbcUsesImplNames(config);
 487             String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
 488             String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
 489 
 490             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
 491             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
 492                             int.class);
 493 
 494             r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
 495             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 496             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 497         }
 498     }
 499 
 500     private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 501         Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
 502         if (config.useMultiplyToLenIntrinsic()) {
 503             assert config.multiplyToLen != 0L;
 504             if (JavaVersionUtil.JAVA_SPEC <= 8) {
 505                 r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
 506                                 int[].class);
 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         boolean useSha1 = config.useSHA1Intrinsics();
 528         boolean useSha256 = config.useSHA256Intrinsics();
 529         boolean useSha512 = config.useSHA512Intrinsics();
 530 
 531         if (JavaVersionUtil.JAVA_SPEC > 8 && (useSha1 || useSha256 || useSha512)) {
 532             Registration r = new Registration(plugins, "sun.security.provider.DigestBase", bytecodeProvider);
 533             r.registerMethodSubstitution(DigestBaseSubstitutions.class, "implCompressMultiBlock0", Receiver.class, byte[].class, int.class, int.class);
 534         }
 535 
 536         if (useSha1) {
 537             assert config.sha1ImplCompress != 0L;
 538             Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider);
 539             r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 540         }
 541         if (useSha256) {
 542             assert config.sha256ImplCompress != 0L;
 543             Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider);
 544             r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 545         }
 546         if (useSha512) {
 547             assert config.sha512ImplCompress != 0L;
 548             Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider);
 549             r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 550         }
 551     }
 552 
 553     private static void registerGHASHPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 554         if (config.useGHASHIntrinsics()) {
 555             assert config.ghashProcessBlocks != 0L;
 556             Registration r = new Registration(plugins, "com.sun.crypto.provider.GHASH");
 557             r.register5("processBlocks",
 558                             byte[].class,
 559                             int.class,
 560                             int.class,
 561                             long[].class,
 562                             long[].class,
 563                             new InvocationPlugin() {
 564                                 @Override
 565                                 public boolean apply(GraphBuilderContext b,
 566                                                 ResolvedJavaMethod targetMethod,
 567                                                 Receiver receiver,
 568                                                 ValueNode data,
 569                                                 ValueNode inOffset,
 570                                                 ValueNode blocks,
 571                                                 ValueNode state,
 572                                                 ValueNode hashSubkey) {
 573                                     int longArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Long);
 574                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 575                                     ValueNode dataOffset = AddNode.create(ConstantNode.forInt(byteArrayBaseOffset), inOffset, NodeView.DEFAULT);
 576                                     ComputeObjectAddressNode dataAddress = b.add(new ComputeObjectAddressNode(data, dataOffset));
 577                                     ComputeObjectAddressNode stateAddress = b.add(new ComputeObjectAddressNode(state, ConstantNode.forInt(longArrayBaseOffset)));
 578                                     ComputeObjectAddressNode hashSubkeyAddress = b.add(new ComputeObjectAddressNode(hashSubkey, ConstantNode.forInt(longArrayBaseOffset)));
 579                                     b.add(new ForeignCallNode(foreignCalls, GHASH_PROCESS_BLOCKS, stateAddress, hashSubkeyAddress, dataAddress, blocks));
 580                                     return true;
 581                                 }
 582                             });
 583         }
 584     }
 585 
 586     private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 587         if (config.useAESCTRIntrinsics) {
 588             assert config.counterModeAESCrypt != 0L;
 589             Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", bytecodeProvider);
 590             r.registerMethodSubstitution(CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
 591         }
 592     }
 593 
 594     private static void registerBase64Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 595         if (config.useBase64Intrinsics()) {
 596             Registration r = new Registration(plugins, "java.util.Base64$Encoder");
 597             r.register7("encodeBlock",
 598                             Receiver.class,
 599                             byte[].class,
 600                             int.class,
 601                             int.class,
 602                             byte[].class,
 603                             int.class,
 604                             boolean.class,
 605                             new InvocationPlugin() {
 606                                 @Override
 607                                 public boolean apply(GraphBuilderContext b,
 608                                                 ResolvedJavaMethod targetMethod,
 609                                                 Receiver receiver,
 610                                                 ValueNode src,
 611                                                 ValueNode sp,
 612                                                 ValueNode sl,
 613                                                 ValueNode dst,
 614                                                 ValueNode dp,
 615                                                 ValueNode isURL) {
 616                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 617                                     ComputeObjectAddressNode srcAddress = b.add(new ComputeObjectAddressNode(src, ConstantNode.forInt(byteArrayBaseOffset)));
 618                                     ComputeObjectAddressNode dstAddress = b.add(new ComputeObjectAddressNode(dst, ConstantNode.forInt(byteArrayBaseOffset)));
 619                                     b.add(new ForeignCallNode(foreignCalls, BASE64_ENCODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL));
 620                                     return true;
 621                                 }
 622                             });
 623         }
 624     }
 625 
 626     private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 627         if (config.useCRC32Intrinsics) {
 628             Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
 629             r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
 630             if (JavaVersionUtil.JAVA_SPEC <= 8) {
 631                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 632                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
 633             } else {
 634                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
 635                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
 636             }
 637         }
 638     }
 639 
 640     private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 641         if (config.useCRC32CIntrinsics) {
 642             Registration r = new Registration(plugins, "java.util.zip.CRC32C", bytecodeProvider);
 643             r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 644             r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
 645         }
 646     }
 647 
 648     private static void registerArraysSupportPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 649         if (config.useVectorizedMismatchIntrinsic) {
 650             Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", bytecodeProvider);
 651             r.registerMethodSubstitution(ArraysSupportSubstitutions.class, "vectorizedMismatch", Object.class, long.class, Object.class, long.class, int.class, int.class);
 652         }
 653     }
 654 }