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 }