1 /*
2  * Copyright (c) 2015, 2018, 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.replacements;
26 
27 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
28 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
29 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
30 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
31 import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD;
32 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
33 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
34 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
35 import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION;
36 import static org.graalvm.compiler.serviceprovider.GraalServices.Java11OrEarlier;
37 import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier;
38 
39 import java.lang.reflect.Array;
40 import java.lang.reflect.Field;
41 import java.util.Arrays;
42 
43 import org.graalvm.compiler.api.directives.GraalDirectives;
44 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
45 import org.graalvm.compiler.bytecode.BytecodeProvider;
46 import org.graalvm.compiler.core.common.calc.Condition;
47 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
48 import org.graalvm.compiler.core.common.calc.UnsignedMath;
49 import org.graalvm.compiler.core.common.type.ObjectStamp;
50 import org.graalvm.compiler.core.common.type.Stamp;
51 import org.graalvm.compiler.core.common.type.StampFactory;
52 import org.graalvm.compiler.core.common.type.TypeReference;
53 import org.graalvm.compiler.debug.GraalError;
54 import org.graalvm.compiler.graph.Edges;
55 import org.graalvm.compiler.graph.Node;
56 import org.graalvm.compiler.graph.NodeList;
57 import org.graalvm.compiler.java.IntegerExactOpSpeculation;
58 import org.graalvm.compiler.java.IntegerExactOpSpeculation.IntegerExactOp;
59 import org.graalvm.compiler.nodes.AbstractBeginNode;
60 import org.graalvm.compiler.nodes.BeginNode;
61 import org.graalvm.compiler.nodes.ConstantNode;
62 import org.graalvm.compiler.nodes.DeoptimizeNode;
63 import org.graalvm.compiler.nodes.EndNode;
64 import org.graalvm.compiler.nodes.FixedGuardNode;
65 import org.graalvm.compiler.nodes.FixedWithNextNode;
66 import org.graalvm.compiler.nodes.IfNode;
67 import org.graalvm.compiler.nodes.LogicNode;
68 import org.graalvm.compiler.nodes.MergeNode;
69 import org.graalvm.compiler.nodes.NodeView;
70 import org.graalvm.compiler.nodes.StateSplit;
71 import org.graalvm.compiler.nodes.StructuredGraph;
72 import org.graalvm.compiler.nodes.ValueNode;
73 import org.graalvm.compiler.nodes.ValuePhiNode;
74 import org.graalvm.compiler.nodes.calc.AbsNode;
75 import org.graalvm.compiler.nodes.calc.CompareNode;
76 import org.graalvm.compiler.nodes.calc.ConditionalNode;
77 import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
78 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
79 import org.graalvm.compiler.nodes.calc.IsNullNode;
80 import org.graalvm.compiler.nodes.calc.NarrowNode;
81 import org.graalvm.compiler.nodes.calc.ReinterpretNode;
82 import org.graalvm.compiler.nodes.calc.RightShiftNode;
83 import org.graalvm.compiler.nodes.calc.SignExtendNode;
84 import org.graalvm.compiler.nodes.calc.SqrtNode;
85 import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
86 import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
87 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
88 import org.graalvm.compiler.nodes.debug.BindToRegisterNode;
89 import org.graalvm.compiler.nodes.debug.BlackholeNode;
90 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
91 import org.graalvm.compiler.nodes.debug.SpillRegistersNode;
92 import org.graalvm.compiler.nodes.extended.BoxNode;
93 import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
94 import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
95 import org.graalvm.compiler.nodes.extended.GetClassNode;
96 import org.graalvm.compiler.nodes.extended.MembarNode;
97 import org.graalvm.compiler.nodes.extended.OpaqueNode;
98 import org.graalvm.compiler.nodes.extended.RawLoadNode;
99 import org.graalvm.compiler.nodes.extended.RawStoreNode;
100 import org.graalvm.compiler.nodes.extended.UnboxNode;
101 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
102 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
103 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
104 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
105 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
106 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
107 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
108 import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
109 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
110 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
111 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
112 import org.graalvm.compiler.nodes.java.LoadFieldNode;
113 import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
114 import org.graalvm.compiler.nodes.java.UnsafeCompareAndExchangeNode;
115 import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
116 import org.graalvm.compiler.nodes.type.StampTool;
117 import org.graalvm.compiler.nodes.util.GraphUtil;
118 import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode;
119 import org.graalvm.compiler.replacements.nodes.ProfileBooleanNode;
120 import org.graalvm.compiler.replacements.nodes.ReverseBytesNode;
121 import org.graalvm.compiler.replacements.nodes.VirtualizableInvokeMacroNode;
122 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactNode;
123 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactSplitNode;
124 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticNode;
125 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticSplitNode;
126 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode;
127 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactSplitNode;
128 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
129 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode;
130 import jdk.internal.vm.compiler.word.LocationIdentity;
131 
132 import jdk.vm.ci.code.BytecodePosition;
133 import jdk.vm.ci.meta.DeoptimizationAction;
134 import jdk.vm.ci.meta.DeoptimizationReason;
135 import jdk.vm.ci.meta.JavaConstant;
136 import jdk.vm.ci.meta.JavaKind;
137 import jdk.vm.ci.meta.MetaAccessProvider;
138 import jdk.vm.ci.meta.ResolvedJavaField;
139 import jdk.vm.ci.meta.ResolvedJavaMethod;
140 import jdk.vm.ci.meta.ResolvedJavaType;
141 import jdk.vm.ci.meta.SpeculationLog;
142 import jdk.vm.ci.meta.SpeculationLog.Speculation;
143 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
144 import sun.misc.Unsafe;
145 
146 /**
147  * Provides non-runtime specific {@link InvocationPlugin}s.
148  */
149 public class StandardGraphBuilderPlugins {
150 
registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean allowDeoptimization, boolean explicitUnsafeNullChecks)151     public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider,
152                     boolean allowDeoptimization, boolean explicitUnsafeNullChecks) {
153         registerObjectPlugins(plugins);
154         registerClassPlugins(plugins);
155         registerMathPlugins(plugins, allowDeoptimization);
156         registerStrictMathPlugins(plugins);
157         registerUnsignedMathPlugins(plugins);
158         registerStringPlugins(plugins, bytecodeProvider, snippetReflection);
159         registerCharacterPlugins(plugins);
160         registerShortPlugins(plugins);
161         registerIntegerLongPlugins(plugins, JavaKind.Int);
162         registerIntegerLongPlugins(plugins, JavaKind.Long);
163         registerFloatPlugins(plugins);
164         registerDoublePlugins(plugins);
165         registerArraysPlugins(plugins, bytecodeProvider);
166         registerArrayPlugins(plugins, bytecodeProvider);
167         registerUnsafePlugins(plugins, bytecodeProvider, explicitUnsafeNullChecks);
168         registerEdgesPlugins(metaAccess, plugins);
169         registerGraalDirectivesPlugins(plugins);
170         registerBoxingPlugins(plugins);
171         registerJMHBlackholePlugins(plugins, bytecodeProvider);
172         registerJFRThrowablePlugins(plugins, bytecodeProvider);
173         registerMethodHandleImplPlugins(plugins, snippetReflection, bytecodeProvider);
174         registerJcovCollectPlugins(plugins, bytecodeProvider);
175     }
176 
177     private static final Field STRING_VALUE_FIELD;
178     private static final Field STRING_CODER_FIELD;
179 
180     static {
181         Field coder = null;
182         try {
183             STRING_VALUE_FIELD = String.class.getDeclaredField("value");
184             if (!Java8OrEarlier) {
185                 coder = String.class.getDeclaredField("coder");
186             }
187         } catch (NoSuchFieldException e) {
188             throw new GraalError(e);
189         }
190         STRING_CODER_FIELD = coder;
191     }
192 
registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection)193     private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection) {
194         final Registration r = new Registration(plugins, String.class, bytecodeProvider);
195         r.register1("hashCode", Receiver.class, new InvocationPlugin() {
196             @Override
197             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
198                 if (receiver.isConstant()) {
199                     String s = snippetReflection.asObject(String.class, (JavaConstant) receiver.get().asConstant());
200                     b.addPush(JavaKind.Int, b.add(ConstantNode.forInt(s.hashCode())));
201                     return true;
202                 }
203                 return false;
204             }
205         });
206 
207         if (Java8OrEarlier) {
208             r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
209 
210             r.register7("indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class, new StringIndexOfConstantPlugin());
211 
212             Registration sr = new Registration(plugins, StringSubstitutions.class);
213             sr.register1("getValue", String.class, new InvocationPlugin() {
214                 @Override
215                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
216                     ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
217                     b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
218                                     b.getOptions(), b.getAssumptions(), value, field, false, false));
219                     return true;
220                 }
221             });
222         } else {
223             r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class);
224 
225             final Registration latin1r = new Registration(plugins, "java.lang.StringLatin1", bytecodeProvider);
226             latin1r.register5("indexOf", byte[].class, int.class, byte[].class, int.class, int.class, new StringLatin1IndexOfConstantPlugin());
227 
228             final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
229             utf16r.register5("indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class, new StringUTF16IndexOfConstantPlugin());
230 
231             Registration sr = new Registration(plugins, JDK9StringSubstitutions.class);
232             sr.register1("getValue", String.class, new InvocationPlugin() {
233                 @Override
234                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
235                     ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
236                     b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
237                                     b.getOptions(), b.getAssumptions(), value, field, false, false));
238                     return true;
239                 }
240             });
241             sr.register1("getCoder", String.class, new InvocationPlugin() {
242                 @Override
243                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
244                     ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_CODER_FIELD);
245                     b.addPush(JavaKind.Int, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
246                                     b.getOptions(), b.getAssumptions(), value, field, false, false));
247                     return true;
248                 }
249             });
250         }
251     }
252 
registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)253     private static void registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
254         Registration r = new Registration(plugins, Arrays.class, bytecodeProvider);
255         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", boolean[].class, boolean[].class);
256         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", byte[].class, byte[].class);
257         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class);
258         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class);
259         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class);
260         r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class);
261     }
262 
registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)263     private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
264         Registration r = new Registration(plugins, Array.class, bytecodeProvider);
265         r.register2("newInstance", Class.class, int.class, new InvocationPlugin() {
266             @Override
267             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) {
268                 b.addPush(JavaKind.Object, new DynamicNewArrayNode(componentType, length, true));
269                 return true;
270             }
271         });
272         r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class);
273     }
274 
275     /**
276      * The intrinsic for {@link Math#sqrt(double)} is shared with {@link StrictMath#sqrt(double)}.
277      *
278      * @see "http://hg.openjdk.java.net/jdk/jdk/file/621efe32eb0b/src/hotspot/share/oops/method.cpp#l1504"
279      */
280     static final class MathSqrtPlugin implements InvocationPlugin {
281         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value)282         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
283             b.push(JavaKind.Double, b.append(SqrtNode.create(value, NodeView.DEFAULT)));
284             return true;
285         }
286     }
287 
288     private abstract static class UnsafeCompareAndUpdatePluginsRegistrar {
register(Registration r, String casPrefix, boolean explicitUnsafeNullChecks, JavaKind[] compareAndSwapTypes, boolean java11OrEarlier)289         public void register(Registration r, String casPrefix, boolean explicitUnsafeNullChecks, JavaKind[] compareAndSwapTypes, boolean java11OrEarlier) {
290             for (JavaKind kind : compareAndSwapTypes) {
291                 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
292                 String kindName = (kind == JavaKind.Object && !java11OrEarlier) ? "Reference" : kind.name();
293                 r.register5(casPrefix + kindName, Receiver.class, Object.class, long.class, javaClass, javaClass, new UnsafeAccessPlugin(returnKind(kind), explicitUnsafeNullChecks) {
294                     @Override
295                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
296                         // Emits a null-check for the otherwise unused receiver
297                         unsafe.get();
298                         createUnsafeAccess(object, b, (obj, loc) -> UnsafeCompareAndUpdatePluginsRegistrar.this.createNode(obj, offset, expected, x, kind, loc));
299                         return true;
300                     }
301                 });
302             }
303         }
304 
createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)305         public abstract FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity);
306 
returnKind(JavaKind accessKind)307         public abstract JavaKind returnKind(JavaKind accessKind);
308     }
309 
310     private static class UnsafeCompareAndSwapPluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar {
311         @Override
createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)312         public FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) {
313             return new UnsafeCompareAndSwapNode(object, offset, expected, newValue, kind, identity);
314         }
315 
316         @Override
returnKind(JavaKind accessKind)317         public JavaKind returnKind(JavaKind accessKind) {
318             return JavaKind.Boolean.getStackKind();
319         }
320     }
321 
322     private static UnsafeCompareAndSwapPluginsRegistrar unsafeCompareAndSwapPluginsRegistrar = new UnsafeCompareAndSwapPluginsRegistrar();
323 
324     private static class UnsafeCompareAndExchangePluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar {
325         @Override
createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)326         public FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) {
327             return new UnsafeCompareAndExchangeNode(object, offset, expected, newValue, kind, identity);
328         }
329 
330         @Override
returnKind(JavaKind accessKind)331         public JavaKind returnKind(JavaKind accessKind) {
332             if (accessKind.isNumericInteger()) {
333                 return accessKind.getStackKind();
334             } else {
335                 return accessKind;
336             }
337         }
338     }
339 
340     private static UnsafeCompareAndExchangePluginsRegistrar unsafeCompareAndExchangePluginsRegistrar = new UnsafeCompareAndExchangePluginsRegistrar();
341 
registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds)342     public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds) {
343         registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
344         if (!Java8OrEarlier) {
345             registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
346         }
347 
348     }
349 
registerPlatformSpecificUnsafePlugins(JavaKind[] supportedCasKinds, Registration r, boolean java8OrEarlier, boolean explicitUnsafeNullChecks)350     private static void registerPlatformSpecificUnsafePlugins(JavaKind[] supportedCasKinds, Registration r, boolean java8OrEarlier, boolean explicitUnsafeNullChecks) {
351         if (java8OrEarlier) {
352             unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSwap", explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true);
353         } else {
354             unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSet", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier);
355             unsafeCompareAndExchangePluginsRegistrar.register(r, "compareAndExchange", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier);
356         }
357     }
358 
registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks)359     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) {
360         registerUnsafePlugins(new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks);
361         if (!Java8OrEarlier) {
362             registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks);
363         }
364     }
365 
registerUnsafePlugins(Registration r, boolean sunMiscUnsafe, boolean explicitUnsafeNullChecks)366     private static void registerUnsafePlugins(Registration r, boolean sunMiscUnsafe, boolean explicitUnsafeNullChecks) {
367         for (JavaKind kind : JavaKind.values()) {
368             if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
369                 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
370                 String kindName = (kind == JavaKind.Object && !sunMiscUnsafe && !Java11OrEarlier) ? "Reference" : kind.name();
371                 String getName = "get" + kindName;
372                 String putName = "put" + kindName;
373                 // Object-based accesses
374                 r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, explicitUnsafeNullChecks));
375                 r.register4(putName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, explicitUnsafeNullChecks));
376                 // Volatile object-based accesses
377                 r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.VOLATILE, explicitUnsafeNullChecks));
378                 r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.VOLATILE, explicitUnsafeNullChecks));
379                 // Ordered object-based accesses
380                 if (sunMiscUnsafe) {
381                     if (kind == JavaKind.Int || kind == JavaKind.Long || kind == JavaKind.Object) {
382                         r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks));
383                     }
384                 } else {
385                     r.register4("put" + kindName + "Release", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks));
386                     r.register3("get" + kindName + "Acquire", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks));
387                     r.register4("put" + kindName + "Opaque", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.OPAQUE, explicitUnsafeNullChecks));
388                     r.register3("get" + kindName + "Opaque", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.OPAQUE, explicitUnsafeNullChecks));
389                 }
390                 if (kind != JavaKind.Boolean && kind != JavaKind.Object) {
391                     // Raw accesses to memory addresses
392                     r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, explicitUnsafeNullChecks));
393                     r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, explicitUnsafeNullChecks));
394                 }
395             }
396         }
397 
398         // Accesses to native memory addresses.
399         r.register2("getAddress", Receiver.class, long.class, new UnsafeGetPlugin(JavaKind.Long, explicitUnsafeNullChecks));
400         r.register3("putAddress", Receiver.class, long.class, long.class, new UnsafePutPlugin(JavaKind.Long, explicitUnsafeNullChecks));
401 
402         r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() {
403 
404             @Override
405             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode clazz) {
406                 // Emits a null-check for the otherwise unused receiver
407                 unsafe.get();
408                 b.addPush(JavaKind.Object, new DynamicNewInstanceNode(b.nullCheckedValue(clazz, DeoptimizationAction.None), true));
409                 return true;
410             }
411 
412         });
413 
414         r.register1("loadFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | LOAD_STORE));
415         r.register1("storeFence", Receiver.class, new UnsafeFencePlugin(STORE_STORE | LOAD_STORE));
416         r.register1("fullFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | STORE_STORE | LOAD_STORE | STORE_LOAD));
417     }
418 
registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind)419     private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind) {
420         Class<?> declaringClass = kind.toBoxedJavaClass();
421         Class<?> type = kind.toJavaClass();
422         Registration r = new Registration(plugins, declaringClass);
423         r.register1("reverseBytes", type, new InvocationPlugin() {
424             @Override
425             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
426                 b.push(kind, b.append(new ReverseBytesNode(value).canonical(null)));
427                 return true;
428             }
429         });
430         r.register2("divideUnsigned", type, type, new InvocationPlugin() {
431             @Override
432             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
433                 b.push(kind, b.append(UnsignedDivNode.create(dividend, divisor, null, NodeView.DEFAULT)));
434                 return true;
435             }
436         });
437         r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
438             @Override
439             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
440                 b.push(kind, b.append(UnsignedRemNode.create(dividend, divisor, null, NodeView.DEFAULT)));
441                 return true;
442             }
443         });
444     }
445 
registerCharacterPlugins(InvocationPlugins plugins)446     private static void registerCharacterPlugins(InvocationPlugins plugins) {
447         Registration r = new Registration(plugins, Character.class);
448         r.register1("reverseBytes", char.class, new InvocationPlugin() {
449             @Override
450             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
451                 // return (char) (Integer.reverse(i) >> 16);
452                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
453                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
454                 ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
455                 b.push(JavaKind.Char, b.append(charCast.canonical(null)));
456                 return true;
457             }
458         });
459     }
460 
registerShortPlugins(InvocationPlugins plugins)461     private static void registerShortPlugins(InvocationPlugins plugins) {
462         Registration r = new Registration(plugins, Short.class);
463         r.register1("reverseBytes", short.class, new InvocationPlugin() {
464             @Override
465             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
466                 // return (short) (Integer.reverse(i) >> 16);
467                 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value));
468                 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16))));
469                 SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32));
470                 b.push(JavaKind.Short, b.append(charCast.canonical(null)));
471                 return true;
472             }
473         });
474     }
475 
registerFloatPlugins(InvocationPlugins plugins)476     private static void registerFloatPlugins(InvocationPlugins plugins) {
477         Registration r = new Registration(plugins, Float.class);
478         r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
479             @Override
480             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
481                 b.push(JavaKind.Int, b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT)));
482                 return true;
483             }
484         });
485         r.register1("floatToIntBits", float.class, new InvocationPlugin() {
486             @Override
487             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
488                 LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
489                 ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT));
490                 ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forInt(0x7fc00000), NodeView.DEFAULT));
491                 b.push(JavaKind.Int, result);
492                 return true;
493             }
494         });
495         r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
496             @Override
497             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
498                 b.push(JavaKind.Float, b.append(ReinterpretNode.create(JavaKind.Float, value, NodeView.DEFAULT)));
499                 return true;
500             }
501         });
502     }
503 
registerDoublePlugins(InvocationPlugins plugins)504     private static void registerDoublePlugins(InvocationPlugins plugins) {
505         Registration r = new Registration(plugins, Double.class);
506         r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
507             @Override
508             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
509                 b.push(JavaKind.Long, b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT)));
510                 return true;
511             }
512         });
513         r.register1("doubleToLongBits", double.class, new InvocationPlugin() {
514             @Override
515             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
516                 LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
517                 ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT));
518                 ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forLong(0x7ff8000000000000L), NodeView.DEFAULT));
519                 b.push(JavaKind.Long, result);
520                 return true;
521             }
522         });
523         r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
524             @Override
525             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
526                 b.push(JavaKind.Double, b.append(ReinterpretNode.create(JavaKind.Double, value, NodeView.DEFAULT)));
527                 return true;
528             }
529         });
530     }
531 
createIntegerExactArithmeticNode(ValueNode x, ValueNode y, SpeculationReason speculation, IntegerExactOp op)532     private static ValueNode createIntegerExactArithmeticNode(ValueNode x, ValueNode y, SpeculationReason speculation, IntegerExactOp op) {
533         switch (op) {
534             case INTEGER_ADD_EXACT:
535             case INTEGER_INCREMENT_EXACT:
536                 return new IntegerAddExactNode(x, y, speculation);
537             case INTEGER_SUBTRACT_EXACT:
538             case INTEGER_DECREMENT_EXACT:
539                 return new IntegerSubExactNode(x, y, speculation);
540             case INTEGER_MULTIPLY_EXACT:
541                 return new IntegerMulExactNode(x, y, speculation);
542             default:
543                 throw GraalError.shouldNotReachHere("Unknown integer exact operation.");
544         }
545     }
546 
createIntegerExactSplit(ValueNode x, ValueNode y, AbstractBeginNode exceptionEdge, IntegerExactOp op)547     private static IntegerExactArithmeticSplitNode createIntegerExactSplit(ValueNode x, ValueNode y, AbstractBeginNode exceptionEdge, IntegerExactOp op) {
548         switch (op) {
549             case INTEGER_ADD_EXACT:
550             case INTEGER_INCREMENT_EXACT:
551                 return new IntegerAddExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
552             case INTEGER_SUBTRACT_EXACT:
553             case INTEGER_DECREMENT_EXACT:
554                 return new IntegerSubExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
555             case INTEGER_MULTIPLY_EXACT:
556                 return new IntegerMulExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
557             default:
558                 throw GraalError.shouldNotReachHere("Unknown integer exact operation.");
559         }
560     }
561 
createIntegerExactOperation(GraphBuilderContext b, JavaKind kind, ValueNode x, ValueNode y, IntegerExactOp op)562     private static boolean createIntegerExactOperation(GraphBuilderContext b, JavaKind kind, ValueNode x, ValueNode y, IntegerExactOp op) {
563         BytecodeExceptionKind exceptionKind = kind == JavaKind.Int ? BytecodeExceptionKind.INTEGER_EXACT_OVERFLOW : BytecodeExceptionKind.LONG_EXACT_OVERFLOW;
564         AbstractBeginNode exceptionEdge = b.genExplicitExceptionEdge(exceptionKind);
565         if (exceptionEdge != null) {
566             IntegerExactArithmeticSplitNode split = b.addPush(kind, createIntegerExactSplit(x, y, exceptionEdge, op));
567             split.setNext(b.add(new BeginNode()));
568             return true;
569         }
570         return false;
571     }
572 
registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization)573     private static void registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization) {
574         Registration r = new Registration(plugins, Math.class);
575         if (allowDeoptimization) {
576             for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) {
577                 Class<?> type = kind.toJavaClass();
578 
579                 r.register1("decrementExact", type, new InvocationPlugin() {
580                     @Override
581                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
582                         ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1));
583                         return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_DECREMENT_EXACT);
584                     }
585                 });
586 
587                 r.register1("incrementExact", type, new InvocationPlugin() {
588                     @Override
589                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
590                         ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1));
591                         return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_INCREMENT_EXACT);
592                     }
593                 });
594 
595                 r.register2("addExact", type, type, new InvocationPlugin() {
596                     @Override
597                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
598                         return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_ADD_EXACT);
599                     }
600                 });
601 
602                 r.register2("subtractExact", type, type, new InvocationPlugin() {
603                     @Override
604                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
605                         return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_SUBTRACT_EXACT);
606                     }
607                 });
608 
609                 r.register2("multiplyExact", type, type, new InvocationPlugin() {
610                     @Override
611                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
612                         return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_MULTIPLY_EXACT);
613                      }
614                 });
615             }
616         }
617         r.register1("abs", Float.TYPE, new InvocationPlugin() {
618 
619             @Override
620             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
621                 b.push(JavaKind.Float, b.append(new AbsNode(value).canonical(null)));
622                 return true;
623             }
624         });
625         r.register1("abs", Double.TYPE, new InvocationPlugin() {
626             @Override
627             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
628                 b.push(JavaKind.Double, b.append(new AbsNode(value).canonical(null)));
629                 return true;
630             }
631         });
632         r.register1("sqrt", Double.TYPE, new MathSqrtPlugin());
633     }
634 
registerStrictMathPlugins(InvocationPlugins plugins)635     private static void registerStrictMathPlugins(InvocationPlugins plugins) {
636         Registration r = new Registration(plugins, StrictMath.class);
637         r.register1("sqrt", Double.TYPE, new MathSqrtPlugin());
638     }
639 
640     public static final class StringIndexOfConstantPlugin implements InvocationPlugin {
641         @Override
inlineOnly()642         public boolean inlineOnly() {
643             return true;
644         }
645 
646         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceOffset, ValueNode sourceCount, ValueNode target, ValueNode targetOffset, ValueNode targetCount, ValueNode origFromIndex)647         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceOffset, ValueNode sourceCount,
648                         ValueNode target, ValueNode targetOffset, ValueNode targetCount, ValueNode origFromIndex) {
649             if (target.isConstant()) {
650                 b.addPush(JavaKind.Int, new StringIndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), source, sourceOffset, sourceCount,
651                                 target, targetOffset, targetCount, origFromIndex));
652                 return true;
653             }
654             return false;
655         }
656     }
657 
658     public static final class StringLatin1IndexOfConstantPlugin implements InvocationPlugin {
659         @Override
inlineOnly()660         public boolean inlineOnly() {
661             return true;
662         }
663 
664         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex)665         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver,
666                         ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex) {
667             if (target.isConstant()) {
668                 b.addPush(JavaKind.Int, new StringLatin1IndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()),
669                                 source, sourceCount, target, targetCount, origFromIndex));
670                 return true;
671             }
672             return false;
673         }
674     }
675 
676     public static final class StringUTF16IndexOfConstantPlugin implements InvocationPlugin {
677         @Override
inlineOnly()678         public boolean inlineOnly() {
679             return true;
680         }
681 
682         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex)683         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver,
684                         ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex) {
685             if (target.isConstant()) {
686                 b.addPush(JavaKind.Int, new StringUTF16IndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()),
687                                 source, sourceCount, target, targetCount, origFromIndex));
688                 return true;
689             }
690             return false;
691         }
692     }
693 
694     public static class UnsignedMathPlugin implements InvocationPlugin {
695         private final Condition condition;
696 
UnsignedMathPlugin(Condition condition)697         public UnsignedMathPlugin(Condition condition) {
698             this.condition = condition;
699         }
700 
701         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y)702         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
703             CanonicalizedCondition canonical = condition.canonicalize();
704             StructuredGraph graph = b.getGraph();
705 
706             ValueNode lhs = canonical.mustMirror() ? y : x;
707             ValueNode rhs = canonical.mustMirror() ? x : y;
708 
709             ValueNode trueValue = ConstantNode.forBoolean(!canonical.mustNegate(), graph);
710             ValueNode falseValue = ConstantNode.forBoolean(canonical.mustNegate(), graph);
711 
712             LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, canonical.getCanonicalCondition(), lhs, rhs, NodeView.DEFAULT);
713             b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue));
714             return true;
715         }
716     }
717 
registerUnsignedMathPlugins(InvocationPlugins plugins)718     private static void registerUnsignedMathPlugins(InvocationPlugins plugins) {
719         Registration r = new Registration(plugins, UnsignedMath.class);
720         r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT));
721         r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT));
722         r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT));
723         r.register2("belowThan", long.class, long.class, new UnsignedMathPlugin(Condition.BT));
724         r.register2("aboveOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.AE));
725         r.register2("aboveOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.AE));
726         r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE));
727         r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE));
728     }
729 
registerBoxingPlugins(InvocationPlugins plugins)730     protected static void registerBoxingPlugins(InvocationPlugins plugins) {
731         for (JavaKind kind : JavaKind.values()) {
732             if (kind.isPrimitive() && kind != JavaKind.Void) {
733                 new BoxPlugin(kind).register(plugins);
734                 new UnboxPlugin(kind).register(plugins);
735             }
736         }
737     }
738 
registerObjectPlugins(InvocationPlugins plugins)739     private static void registerObjectPlugins(InvocationPlugins plugins) {
740         Registration r = new Registration(plugins, Object.class);
741         r.register1("<init>", Receiver.class, new InvocationPlugin() {
742             @Override
743             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
744                 /*
745                  * Object.<init> is a common instrumentation point so only perform this rewrite if
746                  * the current definition is the normal empty method with a single return bytecode.
747                  * The finalizer registration will instead be performed by the BytecodeParser.
748                  */
749                 if (targetMethod.getCodeSize() == 1) {
750                     ValueNode object = receiver.get();
751                     if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
752                         b.add(new RegisterFinalizerNode(object));
753                     }
754                     return true;
755                 }
756                 return false;
757             }
758         });
759         r.register1("getClass", Receiver.class, new InvocationPlugin() {
760             @Override
761             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
762                 ValueNode object = receiver.get();
763                 ValueNode folded = GetClassNode.tryFold(b.getMetaAccess(), b.getConstantReflection(), NodeView.DEFAULT, GraphUtil.originalValue(object));
764                 if (folded != null) {
765                     b.addPush(JavaKind.Object, folded);
766                 } else {
767                     Stamp stamp = StampFactory.objectNonNull(TypeReference.createTrusted(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Class.class)));
768                     b.addPush(JavaKind.Object, new GetClassNode(stamp, object));
769                 }
770                 return true;
771             }
772         });
773     }
774 
registerClassPlugins(InvocationPlugins plugins)775     private static void registerClassPlugins(InvocationPlugins plugins) {
776         Registration r = new Registration(plugins, Class.class);
777         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
778             @Override
779             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
780                 LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), type.get(), object, false));
781                 b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null)));
782                 return true;
783             }
784         });
785         r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
786             @Override
787             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) {
788                 ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(type.get(), otherType));
789                 b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null)));
790                 return true;
791             }
792         });
793 
794         r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
795             @Override
796             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
797                 b.genCheckcastDynamic(object, receiver.get());
798                 return true;
799             }
800 
801             @Override
802             public boolean inlineOnly() {
803                 return true;
804             }
805         });
806     }
807 
808     /**
809      * Substitutions for improving the performance of some critical methods in {@link Edges}. These
810      * substitutions improve the performance by forcing the relevant methods to be inlined
811      * (intrinsification being a special form of inlining) and removing a checked cast.
812      */
registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins)813     private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
814         Registration r = new Registration(plugins, Edges.class);
815         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
816             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
817                 @Override
818                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) {
819                     ObjectStamp stamp = StampFactory.object(TypeReference.createTrusted(b.getAssumptions(), metaAccess.lookupJavaType(c)));
820                     RawLoadNode value = b.add(new RawLoadNode(stamp, node, offset, LocationIdentity.any(), JavaKind.Object));
821                     b.addPush(JavaKind.Object, value);
822                     return true;
823                 }
824             });
825             r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
826                 @Override
827                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) {
828                     b.add(new RawStoreNode(node, offset, value, JavaKind.Object, LocationIdentity.any()));
829                     return true;
830                 }
831             });
832         }
833     }
834 
835     public static class BoxPlugin implements InvocationPlugin {
836 
837         private final JavaKind kind;
838 
BoxPlugin(JavaKind kind)839         BoxPlugin(JavaKind kind) {
840             this.kind = kind;
841         }
842 
843         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value)844         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
845             if (b.parsingIntrinsic()) {
846                 ResolvedJavaMethod rootMethod = b.getGraph().method();
847                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
848                     // Disable invocation plugins for boxing snippets so that the
849                     // original JDK methods are inlined
850                     return false;
851                 }
852             }
853             ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
854             b.addPush(JavaKind.Object, new BoxNode(value, resultType, kind));
855             return true;
856         }
857 
register(InvocationPlugins plugins)858         void register(InvocationPlugins plugins) {
859             plugins.register(this, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
860         }
861     }
862 
863     public static class UnboxPlugin implements InvocationPlugin {
864 
865         private final JavaKind kind;
866 
UnboxPlugin(JavaKind kind)867         UnboxPlugin(JavaKind kind) {
868             this.kind = kind;
869         }
870 
871         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver)872         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
873             if (b.parsingIntrinsic()) {
874                 ResolvedJavaMethod rootMethod = b.getGraph().method();
875                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
876                     // Disable invocation plugins for unboxing snippets so that the
877                     // original JDK methods are inlined
878                     return false;
879                 }
880             }
881             ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind);
882             b.addPush(kind, valueNode);
883             return true;
884         }
885 
register(InvocationPlugins plugins)886         void register(InvocationPlugins plugins) {
887             String name = kind.toJavaClass().getSimpleName() + "Value";
888             plugins.register(this, kind.toBoxedJavaClass(), name, Receiver.class);
889         }
890     }
891 
892     /**
893      * The new memory order modes (JDK9+) are defined with cumulative effect, from weakest to
894      * strongest: Plain, Opaque, Release/Acquire, and Volatile. The existing Plain and Volatile
895      * modes are defined compatibly with their pre-JDK 9 forms. Any guaranteed property of a weaker
896      * mode, plus more, holds for a stronger mode. (Conversely, implementations are allowed to use a
897      * stronger mode than requested for any access.) In JDK 9, these are provided without a full
898      * formal specification.
899      */
900     enum AccessKind {
901         PLAIN(0, 0, 0, 0, false),
902         /**
903          * Opaque accesses are wrapped by dummy membars to avoid floating/hoisting, this is stronger
904          * than required since Opaque mode does not directly impose any ordering constraints with
905          * respect to other variables beyond Plain mode.
906          */
907         OPAQUE(0, 0, 0, 0, true),
908         RELEASE_ACQUIRE(0, LOAD_LOAD | LOAD_STORE, LOAD_STORE | STORE_STORE, 0, true),
909         VOLATILE(JMM_PRE_VOLATILE_READ, JMM_POST_VOLATILE_READ, JMM_PRE_VOLATILE_WRITE, JMM_POST_VOLATILE_WRITE, true);
910 
911         public final boolean emitBarriers;
912         public final int preReadBarriers;
913         public final int postReadBarriers;
914         public final int preWriteBarriers;
915         public final int postWriteBarriers;
916 
AccessKind(int preReadBarriers, int postReadBarriers, int preWriteBarriers, int postWriteBarriers, boolean emitBarriers)917         AccessKind(int preReadBarriers, int postReadBarriers, int preWriteBarriers, int postWriteBarriers, boolean emitBarriers) {
918             this.emitBarriers = emitBarriers;
919             this.preReadBarriers = preReadBarriers;
920             this.postReadBarriers = postReadBarriers;
921             this.preWriteBarriers = preWriteBarriers;
922             this.postWriteBarriers = postWriteBarriers;
923         }
924     }
925 
926     /**
927      * Unsafe access relative to null object is an access to off-heap memory. As linear pointer
928      * compression uses non-zero null, here null object must be replaced with zero constant.
929      */
930     public abstract static class UnsafeAccessPlugin implements InvocationPlugin {
931         @FunctionalInterface
932         public interface UnsafeNodeConstructor {
create(ValueNode value, LocationIdentity location)933             FixedWithNextNode create(ValueNode value, LocationIdentity location);
934         }
935 
936         protected final JavaKind unsafeAccessKind;
937         private final boolean explicitUnsafeNullChecks;
938 
UnsafeAccessPlugin(JavaKind kind, boolean explicitUnsafeNullChecks)939         public UnsafeAccessPlugin(JavaKind kind, boolean explicitUnsafeNullChecks) {
940             unsafeAccessKind = kind;
941             this.explicitUnsafeNullChecks = explicitUnsafeNullChecks;
942         }
943 
createObjectAccessNode(ValueNode value, UnsafeNodeConstructor nodeConstructor)944         private static FixedWithNextNode createObjectAccessNode(ValueNode value, UnsafeNodeConstructor nodeConstructor) {
945             return nodeConstructor.create(value, LocationIdentity.ANY_LOCATION);
946         }
947 
createMemoryAccessNode(StructuredGraph graph, UnsafeNodeConstructor nodeConstructor)948         private static FixedWithNextNode createMemoryAccessNode(StructuredGraph graph, UnsafeNodeConstructor nodeConstructor) {
949             return nodeConstructor.create(ConstantNode.forLong(0L, graph), OFF_HEAP_LOCATION);
950         }
951 
isLoad(ValueNode node)952         private static boolean isLoad(ValueNode node) {
953             return node.getStackKind() != JavaKind.Void;
954         }
955 
setResult(ValueNode node, GraphBuilderContext b)956         private void setResult(ValueNode node, GraphBuilderContext b) {
957             if (isLoad(node)) {
958                 b.addPush(unsafeAccessKind, node);
959             } else {
960                 b.add(node);
961             }
962         }
963 
createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor)964         protected final void createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor) {
965             StructuredGraph graph = b.getGraph();
966             graph.markUnsafeAccess();
967             /* For unsafe access object pointers can only be stored in the heap */
968             if (unsafeAccessKind == JavaKind.Object) {
969                 setResult(createObjectAccessNode(value, nodeConstructor), b);
970             } else if (StampTool.isPointerAlwaysNull(value)) {
971                 setResult(createMemoryAccessNode(graph, nodeConstructor), b);
972             } else if (!explicitUnsafeNullChecks || StampTool.isPointerNonNull(value)) {
973                 setResult(createObjectAccessNode(value, nodeConstructor), b);
974             } else {
975                 FixedWithNextNode objectAccess = graph.add(createObjectAccessNode(value, nodeConstructor));
976                 FixedWithNextNode memoryAccess = graph.add(createMemoryAccessNode(graph, nodeConstructor));
977                 FixedWithNextNode[] accessNodes = new FixedWithNextNode[]{objectAccess, memoryAccess};
978 
979                 LogicNode condition = graph.addOrUniqueWithInputs(IsNullNode.create(value));
980                 b.add(new IfNode(condition, memoryAccess, objectAccess, 0.5));
981 
982                 MergeNode merge = b.append(new MergeNode());
983                 for (FixedWithNextNode node : accessNodes) {
984                     EndNode endNode = graph.add(new EndNode());
985                     node.setNext(endNode);
986                     if (node instanceof StateSplit) {
987                         if (isLoad(node)) {
988                             /*
989                              * Temporarily push the access node so that the frame state has the node
990                              * on the expression stack.
991                              */
992                             b.push(unsafeAccessKind, node);
993                         }
994                         b.setStateAfter((StateSplit) node);
995                         if (isLoad(node)) {
996                             ValueNode popped = b.pop(unsafeAccessKind);
997                             assert popped == node;
998                         }
999                     }
1000                     merge.addForwardEnd(endNode);
1001                 }
1002 
1003                 if (isLoad(objectAccess)) {
1004                     ValuePhiNode phi = new ValuePhiNode(objectAccess.stamp(NodeView.DEFAULT), merge, accessNodes);
1005                     b.push(unsafeAccessKind, graph.addOrUnique(phi));
1006                 }
1007                 b.setStateAfter(merge);
1008             }
1009         }
1010     }
1011 
1012     public static class UnsafeGetPlugin extends UnsafeAccessPlugin {
1013         private final AccessKind accessKind;
1014 
UnsafeGetPlugin(JavaKind returnKind, boolean explicitUnsafeNullChecks)1015         public UnsafeGetPlugin(JavaKind returnKind, boolean explicitUnsafeNullChecks) {
1016             this(returnKind, AccessKind.PLAIN, explicitUnsafeNullChecks);
1017         }
1018 
UnsafeGetPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks)1019         public UnsafeGetPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks) {
1020             super(kind, explicitUnsafeNullChecks);
1021             this.accessKind = accessKind;
1022         }
1023 
1024         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address)1025         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
1026             // Emits a null-check for the otherwise unused receiver
1027             unsafe.get();
1028             b.addPush(unsafeAccessKind, new UnsafeMemoryLoadNode(address, unsafeAccessKind, OFF_HEAP_LOCATION));
1029             b.getGraph().markUnsafeAccess();
1030             return true;
1031         }
1032 
1033         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset)1034         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) {
1035             // Emits a null-check for the otherwise unused receiver
1036             unsafe.get();
1037             if (accessKind.emitBarriers) {
1038                 b.add(new MembarNode(accessKind.preReadBarriers));
1039             }
1040             createUnsafeAccess(object, b, (obj, loc) -> new RawLoadNode(obj, offset, unsafeAccessKind, loc));
1041             if (accessKind.emitBarriers) {
1042                 b.add(new MembarNode(accessKind.postReadBarriers));
1043             }
1044             return true;
1045         }
1046     }
1047 
1048     public static class UnsafePutPlugin extends UnsafeAccessPlugin {
1049         private final AccessKind accessKind;
1050 
UnsafePutPlugin(JavaKind kind, boolean explicitUnsafeNullChecks)1051         public UnsafePutPlugin(JavaKind kind, boolean explicitUnsafeNullChecks) {
1052             this(kind, AccessKind.PLAIN, explicitUnsafeNullChecks);
1053         }
1054 
UnsafePutPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks)1055         private UnsafePutPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks) {
1056             super(kind, explicitUnsafeNullChecks);
1057             this.accessKind = accessKind;
1058         }
1059 
1060         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value)1061         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
1062             assert !accessKind.emitBarriers : "Barriers for address based Unsafe put is not supported.";
1063             // Emits a null-check for the otherwise unused receiver
1064             unsafe.get();
1065             b.add(new UnsafeMemoryStoreNode(address, value, unsafeAccessKind, OFF_HEAP_LOCATION));
1066             b.getGraph().markUnsafeAccess();
1067             return true;
1068         }
1069 
1070         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value)1071         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
1072             // Emits a null-check for the otherwise unused receiver
1073             unsafe.get();
1074             if (accessKind.emitBarriers) {
1075                 b.add(new MembarNode(accessKind.preWriteBarriers));
1076             }
1077             ValueNode maskedValue = b.maskSubWordValue(value, unsafeAccessKind);
1078             createUnsafeAccess(object, b, (obj, loc) -> new RawStoreNode(obj, offset, maskedValue, unsafeAccessKind, loc));
1079             if (accessKind.emitBarriers) {
1080                 b.add(new MembarNode(accessKind.postWriteBarriers));
1081             }
1082             return true;
1083         }
1084     }
1085 
1086     public static class UnsafeFencePlugin implements InvocationPlugin {
1087 
1088         private final int barriers;
1089 
UnsafeFencePlugin(int barriers)1090         public UnsafeFencePlugin(int barriers) {
1091             this.barriers = barriers;
1092         }
1093 
1094         @Override
apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe)1095         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe) {
1096             // Emits a null-check for the otherwise unused receiver
1097             unsafe.get();
1098             b.add(new MembarNode(barriers));
1099             return true;
1100         }
1101     }
1102 
1103     private static final class DirectiveSpeculationReason implements SpeculationLog.SpeculationReason {
1104         private final BytecodePosition pos;
1105 
DirectiveSpeculationReason(BytecodePosition pos)1106         private DirectiveSpeculationReason(BytecodePosition pos) {
1107             this.pos = pos;
1108         }
1109 
1110         @Override
hashCode()1111         public int hashCode() {
1112             return pos.hashCode();
1113         }
1114 
1115         @Override
equals(Object obj)1116         public boolean equals(Object obj) {
1117             return obj instanceof DirectiveSpeculationReason && ((DirectiveSpeculationReason) obj).pos.equals(this.pos);
1118         }
1119     }
1120 
registerGraalDirectivesPlugins(InvocationPlugins plugins)1121     private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
1122         Registration r = new Registration(plugins, GraalDirectives.class);
1123         r.register0("deoptimize", new InvocationPlugin() {
1124             @Override
1125             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1126                 b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
1127                 return true;
1128             }
1129         });
1130 
1131         r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
1132             @Override
1133             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1134                 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
1135                 return true;
1136             }
1137         });
1138 
1139         r.register0("deoptimizeAndInvalidateWithSpeculation", new InvocationPlugin() {
1140             @Override
1141             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1142                 GraalError.guarantee(b.getGraph().getSpeculationLog() != null, "A speculation log is need to use `deoptimizeAndInvalidateWithSpeculation`");
1143                 BytecodePosition pos = new BytecodePosition(null, b.getMethod(), b.bci());
1144                 DirectiveSpeculationReason reason = new DirectiveSpeculationReason(pos);
1145                 Speculation speculation;
1146                 if (b.getGraph().getSpeculationLog().maySpeculate(reason)) {
1147                     speculation = b.getGraph().getSpeculationLog().speculate(reason);
1148                 } else {
1149                     speculation = SpeculationLog.NO_SPECULATION;
1150                 }
1151                 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter, speculation));
1152                 return true;
1153             }
1154         });
1155 
1156         r.register0("inCompiledCode", new InvocationPlugin() {
1157             @Override
1158             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1159                 b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
1160                 return true;
1161             }
1162         });
1163 
1164         r.register0("controlFlowAnchor", new InvocationPlugin() {
1165             @Override
1166             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1167                 b.add(new ControlFlowAnchorNode());
1168                 return true;
1169             }
1170         });
1171 
1172         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
1173             @Override
1174             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
1175                 b.addPush(JavaKind.Boolean, new BranchProbabilityNode(probability, condition));
1176                 return true;
1177             }
1178         });
1179 
1180         InvocationPlugin blackholePlugin = new InvocationPlugin() {
1181             @Override
1182             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
1183                 b.add(new BlackholeNode(value));
1184                 return true;
1185             }
1186         };
1187 
1188         InvocationPlugin bindToRegisterPlugin = new InvocationPlugin() {
1189             @Override
1190             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
1191                 b.add(new BindToRegisterNode(value));
1192                 return true;
1193             }
1194         };
1195         for (JavaKind kind : JavaKind.values()) {
1196             if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
1197                 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
1198                 r.register1("blackhole", javaClass, blackholePlugin);
1199                 r.register1("bindToRegister", javaClass, bindToRegisterPlugin);
1200 
1201                 r.register1("opaque", javaClass, new InvocationPlugin() {
1202                     @Override
1203                     public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
1204                         b.addPush(kind, new OpaqueNode(value));
1205                         return true;
1206                     }
1207                 });
1208             }
1209         }
1210 
1211         InvocationPlugin spillPlugin = new InvocationPlugin() {
1212             @Override
1213             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1214                 b.add(new SpillRegistersNode());
1215                 return true;
1216             }
1217         };
1218         r.register0("spillRegisters", spillPlugin);
1219 
1220         r.register1("guardingNonNull", Object.class, new InvocationPlugin() {
1221             @Override
1222             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
1223                 b.addPush(value.getStackKind(), b.nullCheckedValue(value));
1224                 return true;
1225             }
1226         });
1227 
1228         r.register1("ensureVirtualized", Object.class, new InvocationPlugin() {
1229             @Override
1230             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
1231                 b.add(new EnsureVirtualizedNode(object, false));
1232                 return true;
1233             }
1234         });
1235         r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() {
1236             @Override
1237             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
1238                 b.add(new EnsureVirtualizedNode(object, true));
1239                 return true;
1240             }
1241         });
1242     }
1243 
registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1244     private static void registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
1245         InvocationPlugin blackholePlugin = new InvocationPlugin() {
1246             @Override
1247             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
1248                 blackhole.get();
1249                 b.add(new BlackholeNode(value));
1250                 return true;
1251             }
1252 
1253             @Override
1254             public boolean isDecorator() {
1255                 return true;
1256             }
1257         };
1258         String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
1259         for (String name : names) {
1260             Registration r = new Registration(plugins, name, bytecodeProvider);
1261             for (JavaKind kind : JavaKind.values()) {
1262                 if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) {
1263                     Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
1264                     r.registerOptional2("consume", Receiver.class, javaClass, blackholePlugin);
1265                 }
1266             }
1267             r.registerOptional2("consume", Receiver.class, Object[].class, blackholePlugin);
1268         }
1269     }
1270 
registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1271     private static void registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
1272         Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer", bytecodeProvider);
1273         r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() {
1274             @Override
1275             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) {
1276                 b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), throwable, message));
1277                 return true;
1278             }
1279 
1280             @Override
1281             public boolean inlineOnly() {
1282                 return true;
1283             }
1284         });
1285     }
1286 
registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider)1287     private static void registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) {
1288         Registration r = new Registration(plugins, "java.lang.invoke.MethodHandleImpl", bytecodeProvider);
1289         // In later JDKs this no longer exists and the usage is replace by Class.cast which is
1290         // already an intrinsic
1291         r.registerOptional2("castReference", Class.class, Object.class, new InvocationPlugin() {
1292             @Override
1293             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode javaClass, ValueNode object) {
1294                 b.genCheckcastDynamic(object, javaClass);
1295                 return true;
1296             }
1297 
1298             @Override
1299             public boolean inlineOnly() {
1300                 return true;
1301             }
1302         });
1303         r.register2("profileBoolean", boolean.class, int[].class, new InvocationPlugin() {
1304             @Override
1305             public boolean inlineOnly() {
1306                 return true;
1307             }
1308 
1309             @Override
1310             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode result, ValueNode counters) {
1311                 if (result.isConstant()) {
1312                     b.push(JavaKind.Boolean, result);
1313                     return true;
1314                 }
1315                 if (counters.isConstant()) {
1316                     ValueNode newResult = result;
1317                     int[] ctrs = snippetReflection.asObject(int[].class, (JavaConstant) counters.asConstant());
1318                     if (ctrs != null && ctrs.length == 2) {
1319                         int falseCount = ctrs[0];
1320                         int trueCount = ctrs[1];
1321                         int totalCount = trueCount + falseCount;
1322 
1323                         if (totalCount == 0) {
1324                             b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
1325                         } else if (falseCount == 0 || trueCount == 0) {
1326                             boolean expected = falseCount == 0;
1327                             LogicNode condition = b.addWithInputs(
1328                                             IntegerEqualsNode.create(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, result, b.add(ConstantNode.forBoolean(!expected)),
1329                                                             NodeView.DEFAULT));
1330                             b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true));
1331                             newResult = b.add(ConstantNode.forBoolean(expected));
1332                         } else {
1333                             // We cannot use BranchProbabilityNode here since there's no guarantee
1334                             // the result of MethodHandleImpl.profileBoolean() is used as the
1335                             // test in an `if` statement (as required by BranchProbabilityNode).
1336                         }
1337                     }
1338                     b.addPush(JavaKind.Boolean, newResult);
1339                     return true;
1340                 }
1341                 b.addPush(JavaKind.Boolean,
1342                                 new ProfileBooleanNode(snippetReflection, b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), result, counters));
1343                 return true;
1344             }
1345         });
1346     }
1347 
1348     /**
1349      * Registers a plugin to ignore {@code com.sun.tdk.jcov.runtime.Collect.hit} within an
1350      * intrinsic.
1351      */
registerJcovCollectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1352     private static void registerJcovCollectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
1353         Registration r = new Registration(plugins, "com.sun.tdk.jcov.runtime.Collect", bytecodeProvider);
1354         r.register1("hit", int.class, new InvocationPlugin() {
1355             @Override
1356             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
1357                 if (b.parsingIntrinsic()) {
1358                     return true;
1359                 }
1360                 return false;
1361             }
1362         });
1363     }
1364 }
1365