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.HotSpotGraalRuntimeProvider;
  50 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
  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.word.HotSpotWordTypes;
  73 import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
  74 import org.graalvm.compiler.nodes.ConstantNode;
  75 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  76 import org.graalvm.compiler.nodes.NodeView;
  77 import org.graalvm.compiler.nodes.ValueNode;
  78 import org.graalvm.compiler.nodes.calc.AddNode;
  79 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  80 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  81 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  82 import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
  83 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  85 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  86 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  87 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  88 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  89 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
  90 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
  91 import org.graalvm.compiler.nodes.memory.ReadNode;
  92 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  93 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  94 import org.graalvm.compiler.nodes.util.GraphUtil;
  95 import org.graalvm.compiler.options.OptionValues;
  96 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
  97 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
  98 import org.graalvm.compiler.replacements.MethodHandlePlugin;
  99 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
 100 import org.graalvm.compiler.replacements.ReplacementsImpl;
 101 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
 102 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode;
 103 import org.graalvm.compiler.serviceprovider.GraalServices;
 104 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 105 import org.graalvm.compiler.word.WordOperationPlugin;
 106 import org.graalvm.compiler.word.WordTypes;
 107 import jdk.internal.vm.compiler.word.LocationIdentity;
 108 
 109 import jdk.vm.ci.code.CodeUtil;
 110 import jdk.vm.ci.hotspot.VMIntrinsicMethod;
 111 import jdk.vm.ci.meta.ConstantReflectionProvider;
 112 import jdk.vm.ci.meta.DeoptimizationAction;
 113 import jdk.vm.ci.meta.JavaKind;
 114 import jdk.vm.ci.meta.MetaAccessProvider;
 115 import jdk.vm.ci.meta.ResolvedJavaMethod;
 116 import sun.misc.Unsafe;
 117 
 118 /**
 119  * Defines the {@link Plugins} used when running on HotSpot.
 120  */
 121 public class HotSpotGraphBuilderPlugins {
 122 
 123     /**
 124      * Creates a {@link Plugins} object that should be used when running on HotSpot.
 125      *
 126      * @param constantReflection
 127      * @param snippetReflection
 128      * @param foreignCalls
 129      * @param options
 130      */
 131     public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime,
 132                     CompilerConfiguration compilerConfiguration,
 133                     GraalHotSpotVMConfig config,
 134                     HotSpotWordTypes wordTypes,
 135                     MetaAccessProvider metaAccess,
 136                     ConstantReflectionProvider constantReflection,
 137                     SnippetReflectionProvider snippetReflection,
 138                     ForeignCallsProvider foreignCalls,
 139                     ReplacementsImpl replacements,
 140                     OptionValues options) {
 141         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(graalRuntime, config, compilerConfiguration);
 142 
 143         Plugins plugins = new Plugins(invocationPlugins);
 144         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
 145         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 146         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, config, wordTypes);
 147 
 148         plugins.appendTypePlugin(nodePlugin);
 149         plugins.appendNodePlugin(nodePlugin);
 150         if (!GeneratePIC.getValue(options)) {
 151             plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
 152         }
 153         plugins.appendInlineInvokePlugin(replacements);
 154         if (InlineDuringParsing.getValue(options)) {
 155             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
 156         }
 157 
 158         if (GeneratePIC.getValue(options)) {
 159             plugins.setClassInitializationPlugin(new HotSpotAOTClassInitializationPlugin());
 160             if (TieredAOT.getValue(options)) {
 161                 plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
 162             }
 163         } else {
 164             if (config.instanceKlassInitThreadOffset != -1) {
 165                 plugins.setClassInitializationPlugin(new HotSpotJITClassInitializationPlugin());
 166             }
 167         }
 168 
 169         invocationPlugins.defer(new Runnable() {
 170 
 171             @Override
 172             public void run() {
 173                 BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
 174                 registerObjectPlugins(invocationPlugins, options, config, replacementBytecodeProvider);
 175                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
 176                 registerSystemPlugins(invocationPlugins, foreignCalls);
 177                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
 178                 if (!GeneratePIC.getValue(options)) {
 179                     registerCallSitePlugins(invocationPlugins);
 180                 }
 181                 registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
 182                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
 183                 registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
 184                 registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
 185                 registerCRC32CPlugins(invocationPlugins, config, replacementBytecodeProvider);
 186                 registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
 187                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
 188                 registerGHASHPlugins(invocationPlugins, config, metaAccess, foreignCalls);
 189                 registerCounterModePlugins(invocationPlugins, config, replacementBytecodeProvider);
 190                 registerBase64Plugins(invocationPlugins, config, metaAccess, foreignCalls);
 191                 registerUnsafePlugins(invocationPlugins, config, replacementBytecodeProvider);
 192                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true, false);
 193                 registerArrayPlugins(invocationPlugins, replacementBytecodeProvider);
 194                 registerStringPlugins(invocationPlugins, replacementBytecodeProvider);
 195                 registerArraysSupportPlugins(invocationPlugins, config, replacementBytecodeProvider);
 196 
 197                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
 198                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
 199                 }
 200             }
 201         });
 202         return plugins;
 203     }
 204 
 205     private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 206         Registration r = new Registration(plugins, Object.class, bytecodeProvider);
 207         if (!GeneratePIC.getValue(options)) {
 208             // FIXME: clone() requires speculation and requires a fix in here (to check that
 209             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
 210             // an instantiation of IntrinsicGraphBuilder using a constructor that sets
 211             // AllowAssumptions to YES automatically. The former has to inherit the assumptions
 212             // settings from the root compile instead. So, for now, I'm disabling it for
 213             // GeneratePIC.
 214             r.register1("clone", Receiver.class, new InvocationPlugin() {
 215                 @Override
 216                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 217                     ValueNode object = receiver.get();
 218                     b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
 219                     return true;
 220                 }
 221 
 222                 @Override
 223                 public boolean inlineOnly() {
 224                     return true;
 225                 }
 226             });
 227         }
 228         r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
 229         if (config.inlineNotify()) {
 230             r.registerMethodSubstitution(ObjectSubstitutions.class, "notify", Receiver.class);
 231         }
 232         if (config.inlineNotifyAll()) {
 233             r.registerMethodSubstitution(ObjectSubstitutions.class, "notifyAll", Receiver.class);
 234         }
 235     }
 236 
 237     private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 238         Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
 239 
 240         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
 241         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
 242         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
 243         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
 244         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
 245 
 246         if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
 247             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
 248         }
 249     }
 250 
 251     private static void registerCallSitePlugins(InvocationPlugins plugins) {
 252         InvocationPlugin plugin = new InvocationPlugin() {
 253             @Override
 254             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 255                 ValueNode callSite = receiver.get();
 256                 ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite, true), b.getMetaAccess(), b.getAssumptions());
 257                 if (folded != null) {
 258                     b.addPush(JavaKind.Object, folded);
 259                 } else {
 260                     b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
 261                 }
 262                 return true;
 263             }
 264 
 265             @Override
 266             public boolean inlineOnly() {
 267                 return true;
 268             }
 269         };
 270         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
 271         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
 272         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
 273     }
 274 
 275     private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 276         Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
 277         r.register0("getCallerClass", new InvocationPlugin() {
 278             @Override
 279             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 280                 b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
 281                 return true;
 282             }
 283 
 284             @Override
 285             public boolean inlineOnly() {
 286                 return true;
 287             }
 288         });
 289         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
 290     }
 291 
 292     private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider replacementBytecodeProvider) {
 293         Registration r;
 294         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 295             r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
 296         } else {
 297             r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
 298         }
 299         String substituteMethodName = config.doingUnsafeAccessOffset != Integer.MAX_VALUE ? "copyMemoryGuarded" : "copyMemory";
 300         r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, substituteMethodName, Receiver.class, Object.class, long.class, Object.class,
 301                         long.class, long.class);
 302     }
 303 
 304     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
 305     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 306 
 307     /**
 308      * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
 309      * {@code constantPoolOop} field in a ConstantPool value.
 310      *
 311      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 312      * @return a node representing the metaspace {@code ConstantPool} pointer associated with
 313      *         {@code constantPoolOop}
 314      */
 315     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 316         // ConstantPool.constantPoolOop is in fact the holder class.
 317         ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
 318         ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 319 
 320         boolean notCompressible = false;
 321         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
 322         return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
 323     }
 324 
 325     /**
 326      * Emits a node representing an element in a metaspace {@code ConstantPool}.
 327      *
 328      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 329      */
 330     private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 331         ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 332         int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
 333         ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long), NodeView.DEFAULT), b.add(ConstantNode.forInt(shift))));
 334         ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
 335         AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
 336         boolean notCompressible = false;
 337         ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
 338         b.addPush(elementKind, elementValue);
 339         return true;
 340     }
 341 
 342     private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 343         Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
 344 
 345         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
 346             @Override
 347             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
 348                 boolean notCompressible = false;
 349                 ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 350                 AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
 351                 ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
 352                 b.addPush(JavaKind.Int, length);
 353                 return true;
 354             }
 355         });
 356 
 357         r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 358             @Override
 359             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 360                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
 361             }
 362         });
 363         r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 364             @Override
 365             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 366                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
 367             }
 368         });
 369         r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 370             @Override
 371             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 372                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
 373             }
 374         });
 375         r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 376             @Override
 377             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 378                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
 379             }
 380         });
 381     }
 382 
 383     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
 384         Registration r = new Registration(plugins, System.class);
 385         r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
 386         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
 387         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
 388             @Override
 389             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 390                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 391                 return true;
 392             }
 393 
 394             @Override
 395             public boolean inlineOnly() {
 396                 return true;
 397             }
 398         });
 399         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
 400             @Override
 401             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
 402                 b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
 403                 return true;
 404             }
 405 
 406             @Override
 407             public boolean inlineOnly() {
 408                 return true;
 409             }
 410         });
 411     }
 412 
 413     private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 414         Registration r = new Registration(plugins, Array.class, bytecodeProvider);
 415         r.setAllowOverwrite(true);
 416         r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
 417     }
 418 
 419     private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 420         if (JavaVersionUtil.JAVA_SPEC > 8) {
 421             final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
 422             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "toBytes", char[].class, int.class, int.class);
 423             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
 424         }
 425     }
 426 
 427     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 428         Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
 429         r.register0("currentThread", new InvocationPlugin() {
 430             @Override
 431             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 432                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
 433                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
 434                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
 435                 // JavaThread::_threadObj is never compressed
 436                 ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
 437                 b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
 438                 return true;
 439             }
 440         });
 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 }