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