001/* 002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements; 024 025import static jdk.internal.jvmci.code.MemoryBarriers.*; 026 027import java.lang.reflect.*; 028import java.util.*; 029 030import jdk.internal.jvmci.code.*; 031import jdk.internal.jvmci.common.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.options.*; 034import sun.misc.*; 035 036import com.oracle.graal.api.directives.*; 037import com.oracle.graal.compiler.common.calc.*; 038import com.oracle.graal.compiler.common.type.*; 039import com.oracle.graal.graph.*; 040import com.oracle.graal.graphbuilderconf.*; 041import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver; 042import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration; 043import com.oracle.graal.nodes.*; 044import com.oracle.graal.nodes.calc.*; 045import com.oracle.graal.nodes.debug.*; 046import com.oracle.graal.nodes.extended.*; 047import com.oracle.graal.nodes.java.*; 048import com.oracle.graal.nodes.util.*; 049import com.oracle.graal.nodes.virtual.*; 050import com.oracle.graal.replacements.nodes.*; 051import com.oracle.graal.replacements.nodes.arithmetic.*; 052 053/** 054 * Provides non-runtime specific {@link InvocationPlugin}s. 055 */ 056public class StandardGraphBuilderPlugins { 057 058 // @formatter:off 059 static class Options { 060 @Option(help = "Enable use of intrinsics for the JMH Blackhole class") 061 public static final OptionValue<Boolean> UseBlackholeSubstitution = new OptionValue<>(true); 062 } 063 // @formatter:on 064 065 public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins, boolean useBoxingPlugins) { 066 registerObjectPlugins(plugins); 067 registerClassPlugins(plugins); 068 registerMathPlugins(plugins); 069 registerUnsignedMathPlugins(plugins); 070 registerCharacterPlugins(plugins); 071 registerShortPlugins(plugins); 072 registerIntegerLongPlugins(plugins, Kind.Int); 073 registerIntegerLongPlugins(plugins, Kind.Long); 074 registerFloatPlugins(plugins); 075 registerDoublePlugins(plugins); 076 registerStringPlugins(plugins); 077 registerArraysPlugins(plugins); 078 registerArrayPlugins(plugins); 079 registerUnsafePlugins(plugins); 080 registerEdgesPlugins(metaAccess, plugins); 081 registerGraalDirectivesPlugins(plugins); 082 if (useBoxingPlugins) { 083 registerBoxingPlugins(plugins); 084 } 085 if (Options.UseBlackholeSubstitution.getValue()) { 086 registerJMHBlackholePlugins(plugins); 087 } 088 registerJFRThrowablePlugins(plugins); 089 } 090 091 private static final Field STRING_VALUE_FIELD; 092 093 static { 094 try { 095 STRING_VALUE_FIELD = String.class.getDeclaredField("value"); 096 } catch (NoSuchFieldException e) { 097 throw new JVMCIError(e); 098 } 099 } 100 101 private static void registerStringPlugins(InvocationPlugins plugins) { 102 Registration r = new Registration(plugins, String.class); 103 r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class); 104 105 r = new Registration(plugins, StringSubstitutions.class); 106 r.register1("getValue", String.class, new InvocationPlugin() { 107 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 108 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); 109 b.addPush(Kind.Object, new LoadFieldNode(value, field)); 110 return true; 111 } 112 }); 113 } 114 115 private static void registerArraysPlugins(InvocationPlugins plugins) { 116 Registration r = new Registration(plugins, Arrays.class); 117 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", boolean[].class, boolean[].class); 118 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", byte[].class, byte[].class); 119 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class); 120 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class); 121 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class); 122 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", float[].class, float[].class); 123 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class); 124 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", double[].class, double[].class); 125 } 126 127 private static void registerArrayPlugins(InvocationPlugins plugins) { 128 Registration r = new Registration(plugins, Array.class); 129 r.register2("newInstance", Class.class, int.class, new InvocationPlugin() { 130 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) { 131 b.addPush(Kind.Object, new DynamicNewArrayNode(componentType, length, true)); 132 return true; 133 } 134 }); 135 r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class); 136 } 137 138 private static void registerUnsafePlugins(InvocationPlugins plugins) { 139 Registration r = new Registration(plugins, Unsafe.class); 140 for (Kind kind : Kind.values()) { 141 if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) { 142 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); 143 String kindName = kind.name(); 144 String getName = "get" + kindName; 145 String putName = "put" + kindName; 146 // Object-based accesses 147 r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, false)); 148 r.register4(putName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, false)); 149 // Volatile object-based accesses 150 r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, true)); 151 r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true)); 152 // Ordered object-based accesses 153 if (kind == Kind.Int || kind == Kind.Long || kind == Kind.Object) { 154 r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, true)); 155 } 156 if (kind != Kind.Boolean && kind != Kind.Object) { 157 // Raw accesses to memory addresses 158 r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, false)); 159 r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, false)); 160 } 161 } 162 } 163 164 // Accesses to native memory addresses. 165 r.register2("getAddress", Receiver.class, long.class, new UnsafeGetPlugin(Kind.Long, false)); 166 r.register3("putAddress", Receiver.class, long.class, long.class, new UnsafePutPlugin(Kind.Long, false)); 167 168 for (Kind kind : new Kind[]{Kind.Int, Kind.Long, Kind.Object}) { 169 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); 170 r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() { 171 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { 172 // Emits a null-check for the otherwise unused receiver 173 unsafe.get(); 174 b.addPush(Kind.Int, new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any())); 175 b.getGraph().markUnsafeAccess(); 176 return true; 177 } 178 }); 179 } 180 181 r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() { 182 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode clazz) { 183 // Emits a null-check for the otherwise unused receiver 184 unsafe.get(); 185 b.addPush(Kind.Object, new DynamicNewInstanceNode(clazz, true)); 186 return true; 187 } 188 }); 189 } 190 191 private static void registerIntegerLongPlugins(InvocationPlugins plugins, Kind kind) { 192 Class<?> declaringClass = kind.toBoxedJavaClass(); 193 Class<?> type = kind.toJavaClass(); 194 Registration r = new Registration(plugins, declaringClass); 195 r.register1("reverseBytes", type, new InvocationPlugin() { 196 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 197 b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value))); 198 return true; 199 } 200 }); 201 r.register1("bitCount", type, new InvocationPlugin() { 202 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 203 b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value))); 204 return true; 205 } 206 }); 207 r.register2("divideUnsigned", type, type, new InvocationPlugin() { 208 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { 209 b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor))); 210 return true; 211 } 212 }); 213 r.register2("remainderUnsigned", type, type, new InvocationPlugin() { 214 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { 215 b.push(kind, b.recursiveAppend(new UnsignedRemNode(dividend, divisor).canonical(null, dividend, divisor))); 216 return true; 217 } 218 }); 219 } 220 221 private static void registerCharacterPlugins(InvocationPlugins plugins) { 222 Registration r = new Registration(plugins, Character.class); 223 r.register1("reverseBytes", char.class, new InvocationPlugin() { 224 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 225 // return (char) (Integer.reverse(i) >> 16); 226 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value)); 227 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16)))); 228 ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32)); 229 b.push(Kind.Char, b.recursiveAppend(charCast.canonical(null, value))); 230 return true; 231 } 232 }); 233 } 234 235 private static void registerShortPlugins(InvocationPlugins plugins) { 236 Registration r = new Registration(plugins, Short.class); 237 r.register1("reverseBytes", short.class, new InvocationPlugin() { 238 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 239 // return (short) (Integer.reverse(i) >> 16); 240 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value)); 241 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16)))); 242 SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32)); 243 b.push(Kind.Short, b.recursiveAppend(charCast.canonical(null, value))); 244 return true; 245 } 246 }); 247 } 248 249 private static void registerFloatPlugins(InvocationPlugins plugins) { 250 Registration r = new Registration(plugins, Float.class); 251 r.register1("floatToRawIntBits", float.class, new InvocationPlugin() { 252 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 253 b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value))); 254 return true; 255 } 256 }); 257 r.register1("intBitsToFloat", int.class, new InvocationPlugin() { 258 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 259 b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value))); 260 return true; 261 } 262 }); 263 } 264 265 private static void registerDoublePlugins(InvocationPlugins plugins) { 266 Registration r = new Registration(plugins, Double.class); 267 r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() { 268 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 269 b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value))); 270 return true; 271 } 272 }); 273 r.register1("longBitsToDouble", long.class, new InvocationPlugin() { 274 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 275 b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value))); 276 return true; 277 } 278 }); 279 } 280 281 private static void registerMathPlugins(InvocationPlugins plugins) { 282 Registration r = new Registration(plugins, Math.class); 283 for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) { 284 Class<?> type = kind.toJavaClass(); 285 r.register2("addExact", type, type, new InvocationPlugin() { 286 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 287 b.addPush(kind, new IntegerAddExactNode(x, y)); 288 return true; 289 } 290 }); 291 r.register2("subtractExact", type, type, new InvocationPlugin() { 292 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 293 b.addPush(kind, new IntegerSubExactNode(x, y)); 294 return true; 295 } 296 }); 297 r.register2("multiplyExact", type, type, new InvocationPlugin() { 298 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 299 b.addPush(kind, new IntegerMulExactNode(x, y)); 300 return true; 301 } 302 }); 303 } 304 r.register1("abs", Float.TYPE, new InvocationPlugin() { 305 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 306 b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value))); 307 return true; 308 } 309 }); 310 r.register1("abs", Double.TYPE, new InvocationPlugin() { 311 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 312 b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value))); 313 return true; 314 } 315 }); 316 r.register1("sqrt", Double.TYPE, new InvocationPlugin() { 317 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 318 b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value))); 319 return true; 320 } 321 }); 322 } 323 324 public static class UnsignedMathPlugin implements InvocationPlugin { 325 private final Condition condition; 326 327 public UnsignedMathPlugin(Condition condition) { 328 this.condition = condition; 329 } 330 331 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 332 // the mirroring and negation operations get the condition into canonical form 333 boolean mirror = condition.canonicalMirror(); 334 boolean negate = condition.canonicalNegate(); 335 StructuredGraph graph = b.getGraph(); 336 337 ValueNode lhs = mirror ? y : x; 338 ValueNode rhs = mirror ? x : y; 339 340 ValueNode trueValue = ConstantNode.forBoolean(!negate, graph); 341 ValueNode falseValue = ConstantNode.forBoolean(negate, graph); 342 343 Condition cond = mirror ? condition.mirror() : condition; 344 if (negate) { 345 cond = cond.negate(); 346 } 347 348 LogicNode compare = CompareNode.createCompareNode(graph, cond, lhs, rhs, b.getConstantReflection()); 349 b.addPush(Kind.Boolean, new ConditionalNode(compare, trueValue, falseValue)); 350 return true; 351 } 352 } 353 354 private static void registerUnsignedMathPlugins(InvocationPlugins plugins) { 355 Registration r = new Registration(plugins, UnsignedMath.class); 356 r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT)); 357 r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT)); 358 r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT)); 359 r.register2("belowThan", long.class, long.class, new UnsignedMathPlugin(Condition.BT)); 360 r.register2("aboveOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.AE)); 361 r.register2("aboveOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.AE)); 362 r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE)); 363 r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE)); 364 r.register2("divide", int.class, int.class, new InvocationPlugin() { 365 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 366 b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); 367 return true; 368 } 369 }); 370 r.register2("divide", long.class, long.class, new InvocationPlugin() { 371 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 372 b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y))); 373 return true; 374 } 375 }); 376 r.register2("remainder", int.class, int.class, new InvocationPlugin() { 377 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 378 b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); 379 return true; 380 } 381 }); 382 r.register2("remainder", long.class, long.class, new InvocationPlugin() { 383 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 384 b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y))); 385 return true; 386 } 387 }); 388 } 389 390 protected static void registerBoxingPlugins(InvocationPlugins plugins) { 391 for (Kind kind : Kind.values()) { 392 if (kind.isPrimitive() && kind != Kind.Void) { 393 new BoxPlugin(kind).register(plugins); 394 new UnboxPlugin(kind).register(plugins); 395 } 396 } 397 } 398 399 private static void registerObjectPlugins(InvocationPlugins plugins) { 400 Registration r = new Registration(plugins, Object.class); 401 r.register1("<init>", Receiver.class, new InvocationPlugin() { 402 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 403 ValueNode object = receiver.get(); 404 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) { 405 b.add(new RegisterFinalizerNode(object)); 406 } 407 return true; 408 } 409 }); 410 r.register1("getClass", Receiver.class, new InvocationPlugin() { 411 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 412 ValueNode object = receiver.get(); 413 ValueNode folded = GetClassNode.tryFold(b.getMetaAccess(), GraphUtil.originalValue(object)); 414 if (folded != null) { 415 b.addPush(Kind.Object, folded); 416 } else { 417 Stamp stamp = StampFactory.declaredNonNull(b.getMetaAccess().lookupJavaType(Class.class)); 418 b.addPush(Kind.Object, new GetClassNode(stamp, object)); 419 } 420 return true; 421 } 422 }); 423 } 424 425 private static void registerClassPlugins(InvocationPlugins plugins) { 426 Registration r = new Registration(plugins, Class.class); 427 r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() { 428 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) { 429 LogicNode condition = b.add(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object)); 430 b.push(Kind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null))); 431 return true; 432 } 433 }); 434 r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() { 435 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) { 436 ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType)); 437 b.push(Kind.Boolean, b.recursiveAppend(new ConditionalNode(condition).canonical(null))); 438 return true; 439 } 440 }); 441 } 442 443 /** 444 * Substitutions for improving the performance of some critical methods in {@link Edges}. These 445 * substitutions improve the performance by forcing the relevant methods to be inlined 446 * (intrinsification being a special form of inlining) and removing a checked cast. The latter 447 * cannot be done directly in Java code as {@link DeferredPiNode} is not available to the 448 * project containing {@link Edges}. 449 */ 450 private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) { 451 Registration r = new Registration(plugins, Edges.class); 452 for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) { 453 r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { 454 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) { 455 ValueNode value = b.add(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any())); 456 boolean exactType = false; 457 boolean nonNull = false; 458 b.addPush(Kind.Object, new PiNode(value, metaAccess.lookupJavaType(c), exactType, nonNull)); 459 return true; 460 } 461 }); 462 r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() { 463 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) { 464 b.add(new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any())); 465 return true; 466 } 467 }); 468 } 469 } 470 471 public static class BoxPlugin implements InvocationPlugin { 472 473 private final Kind kind; 474 475 BoxPlugin(Kind kind) { 476 this.kind = kind; 477 } 478 479 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 480 if (b.parsingIntrinsic()) { 481 ResolvedJavaMethod rootMethod = b.getGraph().method(); 482 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { 483 // Disable invocation plugins for boxing snippets so that the 484 // original JDK methods are inlined 485 return false; 486 } 487 } 488 ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); 489 b.addPush(Kind.Object, new BoxNode(value, resultType, kind)); 490 return true; 491 } 492 493 void register(InvocationPlugins plugins) { 494 plugins.register(this, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass()); 495 } 496 } 497 498 public static class UnboxPlugin implements InvocationPlugin { 499 500 private final Kind kind; 501 502 UnboxPlugin(Kind kind) { 503 this.kind = kind; 504 } 505 506 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 507 if (b.parsingIntrinsic()) { 508 ResolvedJavaMethod rootMethod = b.getGraph().method(); 509 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { 510 // Disable invocation plugins for unboxing snippets so that the 511 // original JDK methods are inlined 512 return false; 513 } 514 } 515 ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind); 516 b.addPush(kind, valueNode); 517 return true; 518 } 519 520 void register(InvocationPlugins plugins) { 521 String name = kind.toJavaClass().getSimpleName() + "Value"; 522 plugins.register(this, kind.toBoxedJavaClass(), name, Receiver.class); 523 } 524 } 525 526 public static class UnsafeGetPlugin implements InvocationPlugin { 527 528 private final Kind returnKind; 529 private final boolean isVolatile; 530 531 public UnsafeGetPlugin(Kind returnKind, boolean isVolatile) { 532 this.returnKind = returnKind; 533 this.isVolatile = isVolatile; 534 } 535 536 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { 537 // Emits a null-check for the otherwise unused receiver 538 unsafe.get(); 539 b.addPush(returnKind, new DirectReadNode(address, returnKind)); 540 b.getGraph().markUnsafeAccess(); 541 return true; 542 } 543 544 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) { 545 // Emits a null-check for the otherwise unused receiver 546 unsafe.get(); 547 if (isVolatile) { 548 b.add(new MembarNode(JMM_PRE_VOLATILE_READ)); 549 } 550 b.addPush(returnKind, new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.any())); 551 if (isVolatile) { 552 b.add(new MembarNode(JMM_POST_VOLATILE_READ)); 553 } 554 b.getGraph().markUnsafeAccess(); 555 return true; 556 } 557 } 558 559 public static class UnsafePutPlugin implements InvocationPlugin { 560 561 private final Kind kind; 562 private final boolean isVolatile; 563 564 public UnsafePutPlugin(Kind kind, boolean isVolatile) { 565 this.kind = kind; 566 this.isVolatile = isVolatile; 567 } 568 569 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { 570 // Emits a null-check for the otherwise unused receiver 571 unsafe.get(); 572 b.add(new DirectStoreNode(address, value, kind)); 573 b.getGraph().markUnsafeAccess(); 574 return true; 575 } 576 577 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { 578 // Emits a null-check for the otherwise unused receiver 579 unsafe.get(); 580 if (isVolatile) { 581 b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); 582 } 583 b.add(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.any())); 584 if (isVolatile) { 585 b.add(new MembarNode(JMM_PRE_VOLATILE_WRITE)); 586 } 587 b.getGraph().markUnsafeAccess(); 588 return true; 589 } 590 } 591 592 private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) { 593 Registration r = new Registration(plugins, GraalDirectives.class); 594 r.register0("deoptimize", new InvocationPlugin() { 595 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 596 b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); 597 return true; 598 } 599 }); 600 601 r.register0("deoptimizeAndInvalidate", new InvocationPlugin() { 602 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 603 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); 604 return true; 605 } 606 }); 607 608 r.register0("inCompiledCode", new InvocationPlugin() { 609 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 610 b.addPush(Kind.Boolean, ConstantNode.forBoolean(true)); 611 return true; 612 } 613 }); 614 615 r.register0("controlFlowAnchor", new InvocationPlugin() { 616 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 617 b.add(new ControlFlowAnchorNode()); 618 return true; 619 } 620 }); 621 622 r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { 623 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { 624 b.addPush(Kind.Boolean, new BranchProbabilityNode(probability, condition)); 625 return true; 626 } 627 }); 628 629 InvocationPlugin blackholePlugin = new InvocationPlugin() { 630 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 631 b.add(new BlackholeNode(value)); 632 return true; 633 } 634 }; 635 636 for (Kind kind : Kind.values()) { 637 if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) { 638 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); 639 r.register1("blackhole", javaClass, blackholePlugin); 640 641 r.register1("opaque", javaClass, new InvocationPlugin() { 642 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 643 b.addPush(kind, new OpaqueNode(value)); 644 return true; 645 } 646 }); 647 } 648 } 649 650 r.register1("guardingNonNull", Object.class, new InvocationPlugin() { 651 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 652 ObjectStamp objectStamp = (ObjectStamp) value.stamp(); 653 if (objectStamp.nonNull()) { 654 b.addPush(value.getKind(), value); 655 return true; 656 } else if (objectStamp.alwaysNull()) { 657 b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.NullCheckException)); 658 return true; 659 } 660 IsNullNode isNull = b.add(new IsNullNode(value)); 661 FixedGuardNode fixedGuard = b.add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true)); 662 Stamp newStamp = objectStamp.improveWith(StampFactory.objectNonNull()); 663 b.addPush(value.getKind(), new PiNode(value, newStamp, fixedGuard)); 664 return true; 665 } 666 }); 667 668 r.register1("ensureVirtualized", Object.class, new InvocationPlugin() { 669 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 670 b.add(new EnsureVirtualizedNode(object, false)); 671 return true; 672 } 673 }); 674 r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() { 675 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 676 b.add(new EnsureVirtualizedNode(object, true)); 677 return true; 678 } 679 }); 680 } 681 682 private static void registerJMHBlackholePlugins(InvocationPlugins plugins) { 683 InvocationPlugin blackholePlugin = new InvocationPlugin() { 684 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) { 685 blackhole.get(); 686 b.add(new BlackholeNode(value)); 687 return true; 688 } 689 }; 690 String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"}; 691 for (String name : names) { 692 Class<?> blackholeClass; 693 blackholeClass = MethodSubstitutionPlugin.resolveClass(name, true); 694 if (blackholeClass != null) { 695 Registration r = new Registration(plugins, blackholeClass); 696 for (Kind kind : Kind.values()) { 697 if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) { 698 Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass(); 699 r.register2("consume", Receiver.class, javaClass, blackholePlugin); 700 } 701 } 702 r.register2("consume", Receiver.class, Object[].class, blackholePlugin); 703 } 704 } 705 } 706 707 private static void registerJFRThrowablePlugins(InvocationPlugins plugins) { 708 String name = "oracle.jrockit.jfr.jdkevents.ThrowableTracer"; 709 Class<?> tracerClass = MethodSubstitutionPlugin.resolveClass(name, true); 710 if (tracerClass != null) { 711 Registration r = new Registration(plugins, tracerClass); 712 r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() { 713 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) { 714 b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), throwable, message)); 715 return true; 716 } 717 }); 718 } 719 } 720}