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 {
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
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 });
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
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
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
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
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 }
1083 }
1084 }
1085
1086 public static class UnsafeFencePlugin implements InvocationPlugin {
1087
1088 private final int barriers;
1089
1090 public UnsafeFencePlugin(int barriers) {
1091 this.barriers = barriers;
1092 }
1093
1094 @Override
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
1106 private DirectiveSpeculationReason(BytecodePosition pos) {
1107 this.pos = pos;
1108 }
1109
1110 @Override
1111 public int hashCode() {
1112 return pos.hashCode();
1113 }
1114
1115 @Override
1116 public boolean equals(Object obj) {
1117 return obj instanceof DirectiveSpeculationReason && ((DirectiveSpeculationReason) obj).pos.equals(this.pos);
1118 }
1119 }
1120
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() {
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
|
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.JavaVersionUtil.Java11OrEarlier;
37 import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.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.nodes.AbstractBeginNode;
58 import org.graalvm.compiler.nodes.BeginNode;
59 import org.graalvm.compiler.nodes.ConstantNode;
60 import org.graalvm.compiler.nodes.DeoptimizeNode;
61 import org.graalvm.compiler.nodes.EndNode;
62 import org.graalvm.compiler.nodes.FixedGuardNode;
63 import org.graalvm.compiler.nodes.FixedWithNextNode;
64 import org.graalvm.compiler.nodes.IfNode;
65 import org.graalvm.compiler.nodes.LogicNode;
66 import org.graalvm.compiler.nodes.MergeNode;
67 import org.graalvm.compiler.nodes.NamedLocationIdentity;
68 import org.graalvm.compiler.nodes.NodeView;
69 import org.graalvm.compiler.nodes.StateSplit;
70 import org.graalvm.compiler.nodes.StructuredGraph;
71 import org.graalvm.compiler.nodes.ValueNode;
72 import org.graalvm.compiler.nodes.ValuePhiNode;
73 import org.graalvm.compiler.nodes.calc.AbsNode;
74 import org.graalvm.compiler.nodes.calc.CompareNode;
75 import org.graalvm.compiler.nodes.calc.ConditionalNode;
76 import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
77 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
78 import org.graalvm.compiler.nodes.calc.IsNullNode;
79 import org.graalvm.compiler.nodes.calc.NarrowNode;
80 import org.graalvm.compiler.nodes.calc.ReinterpretNode;
81 import org.graalvm.compiler.nodes.calc.RightShiftNode;
82 import org.graalvm.compiler.nodes.calc.SignExtendNode;
83 import org.graalvm.compiler.nodes.calc.SqrtNode;
84 import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
85 import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
86 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
87 import org.graalvm.compiler.nodes.debug.BindToRegisterNode;
88 import org.graalvm.compiler.nodes.debug.BlackholeNode;
89 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
90 import org.graalvm.compiler.nodes.debug.SpillRegistersNode;
91 import org.graalvm.compiler.nodes.extended.BoxNode;
92 import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
93 import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
94 import org.graalvm.compiler.nodes.extended.GetClassNode;
95 import org.graalvm.compiler.nodes.extended.GuardingNode;
96 import org.graalvm.compiler.nodes.extended.JavaReadNode;
97 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
98 import org.graalvm.compiler.nodes.extended.MembarNode;
99 import org.graalvm.compiler.nodes.extended.OpaqueNode;
100 import org.graalvm.compiler.nodes.extended.RawLoadNode;
101 import org.graalvm.compiler.nodes.extended.RawStoreNode;
102 import org.graalvm.compiler.nodes.extended.UnboxNode;
103 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
104 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
105 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
106 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
107 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
108 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
109 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
110 import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode;
111 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
112 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
113 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
114 import org.graalvm.compiler.nodes.java.LoadFieldNode;
115 import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
116 import org.graalvm.compiler.nodes.java.UnsafeCompareAndExchangeNode;
117 import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
118 import org.graalvm.compiler.nodes.memory.HeapAccess;
119 import org.graalvm.compiler.nodes.memory.address.IndexAddressNode;
120 import org.graalvm.compiler.nodes.type.StampTool;
121 import org.graalvm.compiler.nodes.util.GraphUtil;
122 import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode;
123 import org.graalvm.compiler.replacements.nodes.ProfileBooleanNode;
124 import org.graalvm.compiler.replacements.nodes.ReverseBytesNode;
125 import org.graalvm.compiler.replacements.nodes.VirtualizableInvokeMacroNode;
126 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactNode;
127 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactOverflowNode;
128 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactSplitNode;
129 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticSplitNode;
130 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode;
131 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactOverflowNode;
132 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactSplitNode;
133 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
134 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactOverflowNode;
135 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode;
136 import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup;
137 import jdk.internal.vm.compiler.word.LocationIdentity;
138
139 import jdk.vm.ci.code.BytecodePosition;
140 import jdk.vm.ci.meta.DeoptimizationAction;
141 import jdk.vm.ci.meta.DeoptimizationReason;
142 import jdk.vm.ci.meta.JavaConstant;
143 import jdk.vm.ci.meta.JavaKind;
144 import jdk.vm.ci.meta.MetaAccessProvider;
145 import jdk.vm.ci.meta.ResolvedJavaField;
146 import jdk.vm.ci.meta.ResolvedJavaMethod;
147 import jdk.vm.ci.meta.ResolvedJavaType;
148 import jdk.vm.ci.meta.SpeculationLog;
149 import jdk.vm.ci.meta.SpeculationLog.Speculation;
150 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
151 import sun.misc.Unsafe;
152
153 /**
154 * Provides non-runtime specific {@link InvocationPlugin}s.
155 */
156 public class StandardGraphBuilderPlugins {
187 static {
188 Field coder = null;
189 try {
190 STRING_VALUE_FIELD = String.class.getDeclaredField("value");
191 if (!Java8OrEarlier) {
192 coder = String.class.getDeclaredField("coder");
193 }
194 } catch (NoSuchFieldException e) {
195 throw new GraalError(e);
196 }
197 STRING_CODER_FIELD = coder;
198 }
199
200 private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection) {
201 final Registration r = new Registration(plugins, String.class, bytecodeProvider);
202 r.register1("hashCode", Receiver.class, new InvocationPlugin() {
203 @Override
204 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
205 if (receiver.isConstant()) {
206 String s = snippetReflection.asObject(String.class, (JavaConstant) receiver.get().asConstant());
207 if (s != null) {
208 b.addPush(JavaKind.Int, b.add(ConstantNode.forInt(s.hashCode())));
209 return true;
210 }
211 }
212 return false;
213 }
214 });
215
216 if (Java8OrEarlier) {
217 r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class);
218
219 r.register7("indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class, new StringIndexOfConstantPlugin());
220
221 Registration sr = new Registration(plugins, StringSubstitutions.class);
222 sr.register1("getValue", String.class, new InvocationPlugin() {
223 @Override
224 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
225 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
226 b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
227 b.getOptions(), b.getAssumptions(), value, field, false, false));
228 return true;
229 }
230 });
231 } else {
232 r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class);
233 Registration utf16sub = new Registration(plugins, StringUTF16Substitutions.class, bytecodeProvider);
234 utf16sub.register2("getCharDirect", byte[].class, int.class, new InvocationPlugin() {
235 @Override
236 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
237 b.addPush(JavaKind.Char, new JavaReadNode(JavaKind.Char, new IndexAddressNode(arg1, arg2, JavaKind.Byte), NamedLocationIdentity.getArrayLocation(JavaKind.Byte),
238 HeapAccess.BarrierType.NONE, false));
239 return true;
240 }
241 });
242 utf16sub.register3("putCharDirect", byte[].class, int.class, int.class, new InvocationPlugin() {
243 @Override
244 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
245 b.add(new JavaWriteNode(JavaKind.Char, new IndexAddressNode(arg1, arg2, JavaKind.Byte), NamedLocationIdentity.getArrayLocation(JavaKind.Byte), arg3,
246 HeapAccess.BarrierType.NONE, false));
247 return true;
248 }
249 });
250
251 final Registration latin1r = new Registration(plugins, "java.lang.StringLatin1", bytecodeProvider);
252 latin1r.register5("indexOf", byte[].class, int.class, byte[].class, int.class, int.class, new StringLatin1IndexOfConstantPlugin());
253
254 final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider);
255 utf16r.register5("indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class, new StringUTF16IndexOfConstantPlugin());
256 utf16r.setAllowOverwrite(true);
257 utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChar", byte[].class, int.class);
258 utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "putChar", byte[].class, int.class, int.class);
259
260 Registration sr = new Registration(plugins, JDK9StringSubstitutions.class);
261 sr.register1("getValue", String.class, new InvocationPlugin() {
262 @Override
263 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
264 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD);
265 b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
266 b.getOptions(), b.getAssumptions(), value, field, false, false));
267 return true;
268 }
269 });
270 sr.register1("getCoder", String.class, new InvocationPlugin() {
271 @Override
272 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
273 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_CODER_FIELD);
274 b.addPush(JavaKind.Int, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(),
275 b.getOptions(), b.getAssumptions(), value, field, false, false));
276 return true;
277 }
278 });
541 });
542 r.register1("doubleToLongBits", double.class, new InvocationPlugin() {
543 @Override
544 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
545 LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
546 ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT));
547 ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forLong(0x7ff8000000000000L), NodeView.DEFAULT));
548 b.push(JavaKind.Long, result);
549 return true;
550 }
551 });
552 r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
553 @Override
554 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
555 b.push(JavaKind.Double, b.append(ReinterpretNode.create(JavaKind.Double, value, NodeView.DEFAULT)));
556 return true;
557 }
558 });
559 }
560
561 public enum IntegerExactOp {
562 INTEGER_ADD_EXACT,
563 INTEGER_INCREMENT_EXACT,
564 INTEGER_SUBTRACT_EXACT,
565 INTEGER_DECREMENT_EXACT,
566 INTEGER_MULTIPLY_EXACT
567 }
568
569 private static GuardingNode createIntegerExactArithmeticGuardNode(GraphBuilderContext b, ValueNode x, ValueNode y, IntegerExactOp op) {
570 LogicNode overflowCheck;
571 switch (op) {
572 case INTEGER_ADD_EXACT:
573 case INTEGER_INCREMENT_EXACT: {
574 overflowCheck = new IntegerAddExactOverflowNode(x, y);
575 break;
576 }
577 case INTEGER_SUBTRACT_EXACT:
578 case INTEGER_DECREMENT_EXACT: {
579 overflowCheck = new IntegerSubExactOverflowNode(x, y);
580 break;
581 }
582 case INTEGER_MULTIPLY_EXACT: {
583 overflowCheck = new IntegerMulExactOverflowNode(x, y);
584 break;
585 }
586 default:
587 throw GraalError.shouldNotReachHere("Unknown integer exact operation.");
588 }
589 return b.add(new FixedGuardNode(overflowCheck, DeoptimizationReason.ArithmeticException, DeoptimizationAction.InvalidateRecompile, true));
590 }
591
592 private static ValueNode createIntegerExactArithmeticNode(GraphBuilderContext b, ValueNode x, ValueNode y, IntegerExactOp op) {
593 switch (op) {
594 case INTEGER_ADD_EXACT:
595 case INTEGER_INCREMENT_EXACT:
596 return new IntegerAddExactNode(x, y, createIntegerExactArithmeticGuardNode(b, x, y, op));
597 case INTEGER_SUBTRACT_EXACT:
598 case INTEGER_DECREMENT_EXACT:
599 return new IntegerSubExactNode(x, y, createIntegerExactArithmeticGuardNode(b, x, y, op));
600 case INTEGER_MULTIPLY_EXACT:
601 return new IntegerMulExactNode(x, y, createIntegerExactArithmeticGuardNode(b, x, y, op));
602 default:
603 throw GraalError.shouldNotReachHere("Unknown integer exact operation.");
604 }
605 }
606
607 private static IntegerExactArithmeticSplitNode createIntegerExactSplit(ValueNode x, ValueNode y, AbstractBeginNode exceptionEdge, IntegerExactOp op) {
608 switch (op) {
609 case INTEGER_ADD_EXACT:
610 case INTEGER_INCREMENT_EXACT:
611 return new IntegerAddExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
612 case INTEGER_SUBTRACT_EXACT:
613 case INTEGER_DECREMENT_EXACT:
614 return new IntegerSubExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
615 case INTEGER_MULTIPLY_EXACT:
616 return new IntegerMulExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge);
617 default:
618 throw GraalError.shouldNotReachHere("Unknown integer exact operation.");
619 }
620 }
621
622 private static void createIntegerExactOperation(GraphBuilderContext b, JavaKind kind, ValueNode x, ValueNode y, IntegerExactOp op) {
623 if (b.needsExplicitException()) {
624 BytecodeExceptionKind exceptionKind = kind == JavaKind.Int ? BytecodeExceptionKind.INTEGER_EXACT_OVERFLOW : BytecodeExceptionKind.LONG_EXACT_OVERFLOW;
625 AbstractBeginNode exceptionEdge = b.genExplicitExceptionEdge(exceptionKind);
626 IntegerExactArithmeticSplitNode split = b.addPush(kind, createIntegerExactSplit(x, y, exceptionEdge, op));
627 split.setNext(b.add(new BeginNode()));
628 } else {
629 b.addPush(kind, createIntegerExactArithmeticNode(b, x, y, op));
630 }
631 }
632
633 private static void registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization) {
634 Registration r = new Registration(plugins, Math.class);
635 if (allowDeoptimization) {
636 for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) {
637 Class<?> type = kind.toJavaClass();
638 r.register1("decrementExact", type, new InvocationPlugin() {
639 @Override
640 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
641 ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1));
642 createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_DECREMENT_EXACT);
643 return true;
644 }
645 });
646
647 r.register1("incrementExact", type, new InvocationPlugin() {
648 @Override
649 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) {
650 ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1));
651 createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_INCREMENT_EXACT);
652 return true;
653 }
654 });
655 r.register2("addExact", type, type, new InvocationPlugin() {
656 @Override
657 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
658 createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_ADD_EXACT);
659 return true;
660 }
661 });
662 r.register2("subtractExact", type, type, new InvocationPlugin() {
663 @Override
664 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
665 createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_SUBTRACT_EXACT);
666 return true;
667 }
668 });
669
670 r.register2("multiplyExact", type, type, new InvocationPlugin() {
671 @Override
672 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
673 createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_MULTIPLY_EXACT);
674 return true;
675 }
676 });
677 }
678 }
679 r.register1("abs", Float.TYPE, new InvocationPlugin() {
680
681 @Override
682 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
683 b.push(JavaKind.Float, b.append(new AbsNode(value).canonical(null)));
684 return true;
685 }
686 });
687 r.register1("abs", Double.TYPE, new InvocationPlugin() {
688 @Override
689 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
690 b.push(JavaKind.Double, b.append(new AbsNode(value).canonical(null)));
691 return true;
692 }
693 });
694 r.register1("sqrt", Double.TYPE, new MathSqrtPlugin());
695 }
1145 }
1146 }
1147
1148 public static class UnsafeFencePlugin implements InvocationPlugin {
1149
1150 private final int barriers;
1151
1152 public UnsafeFencePlugin(int barriers) {
1153 this.barriers = barriers;
1154 }
1155
1156 @Override
1157 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe) {
1158 // Emits a null-check for the otherwise unused receiver
1159 unsafe.get();
1160 b.add(new MembarNode(barriers));
1161 return true;
1162 }
1163 }
1164
1165 private static final SpeculationReasonGroup DIRECTIVE_SPECULATIONS = new SpeculationReasonGroup("GraalDirective", BytecodePosition.class);
1166
1167 private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
1168 Registration r = new Registration(plugins, GraalDirectives.class);
1169 r.register0("deoptimize", new InvocationPlugin() {
1170 @Override
1171 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1172 b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
1173 return true;
1174 }
1175 });
1176
1177 r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
1178 @Override
1179 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1180 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
1181 return true;
1182 }
1183 });
1184
1185 r.register0("deoptimizeAndInvalidateWithSpeculation", new InvocationPlugin() {
1186 @Override
1187 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1188 GraalError.guarantee(b.getGraph().getSpeculationLog() != null, "A speculation log is needed to use `deoptimizeAndInvalidateWithSpeculation`");
1189 BytecodePosition pos = new BytecodePosition(null, b.getMethod(), b.bci());
1190 SpeculationReason reason = DIRECTIVE_SPECULATIONS.createSpeculationReason(pos);
1191 Speculation speculation;
1192 if (b.getGraph().getSpeculationLog().maySpeculate(reason)) {
1193 speculation = b.getGraph().getSpeculationLog().speculate(reason);
1194 } else {
1195 speculation = SpeculationLog.NO_SPECULATION;
1196 }
1197 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter, speculation));
1198 return true;
1199 }
1200 });
1201
1202 r.register0("inCompiledCode", new InvocationPlugin() {
1203 @Override
1204 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
1205 b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true));
1206 return true;
1207 }
1208 });
1209
1210 r.register0("controlFlowAnchor", new InvocationPlugin() {
1353 }
1354
1355 @Override
1356 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode result, ValueNode counters) {
1357 if (result.isConstant()) {
1358 b.push(JavaKind.Boolean, result);
1359 return true;
1360 }
1361 if (counters.isConstant()) {
1362 ValueNode newResult = result;
1363 int[] ctrs = snippetReflection.asObject(int[].class, (JavaConstant) counters.asConstant());
1364 if (ctrs != null && ctrs.length == 2) {
1365 int falseCount = ctrs[0];
1366 int trueCount = ctrs[1];
1367 int totalCount = trueCount + falseCount;
1368
1369 if (totalCount == 0) {
1370 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
1371 } else if (falseCount == 0 || trueCount == 0) {
1372 boolean expected = falseCount == 0;
1373 LogicNode condition = b.add(
1374 IntegerEqualsNode.create(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, result, b.add(ConstantNode.forBoolean(!expected)),
1375 NodeView.DEFAULT));
1376 b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true));
1377 newResult = b.add(ConstantNode.forBoolean(expected));
1378 } else {
1379 // We cannot use BranchProbabilityNode here since there's no guarantee
1380 // the result of MethodHandleImpl.profileBoolean() is used as the
1381 // test in an `if` statement (as required by BranchProbabilityNode).
1382 }
1383 }
1384 b.addPush(JavaKind.Boolean, newResult);
1385 return true;
1386 }
1387 b.addPush(JavaKind.Boolean,
1388 new ProfileBooleanNode(snippetReflection, b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), result, counters));
1389 return true;
1390 }
1391 });
1392 }
1393
|