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