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 }