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 package org.graalvm.compiler.replacements;
24
25 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
26 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
27 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
28 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
29 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
30 import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException;
31 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
32 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
33 import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
34 import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull;
35
36 import java.util.ArrayList;
37 import java.util.BitSet;
38 import java.util.List;
39
40 import org.graalvm.compiler.api.directives.GraalDirectives;
41 import org.graalvm.compiler.api.replacements.Snippet;
42 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
43 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
44 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
45 import org.graalvm.compiler.core.common.type.IntegerStamp;
46 import org.graalvm.compiler.core.common.type.Stamp;
47 import org.graalvm.compiler.core.common.type.StampFactory;
48 import org.graalvm.compiler.core.common.type.TypeReference;
49 import org.graalvm.compiler.debug.DebugHandlersFactory;
50 import org.graalvm.compiler.debug.GraalError;
51 import org.graalvm.compiler.graph.Node;
52 import org.graalvm.compiler.nodeinfo.InputType;
53 import org.graalvm.compiler.nodes.ConstantNode;
54 import org.graalvm.compiler.nodes.FieldLocationIdentity;
55 import org.graalvm.compiler.nodes.FixedNode;
56 import org.graalvm.compiler.nodes.LogicNode;
57 import org.graalvm.compiler.nodes.NamedLocationIdentity;
58 import org.graalvm.compiler.nodes.PiNode;
59 import org.graalvm.compiler.nodes.StructuredGraph;
60 import org.graalvm.compiler.nodes.ValueNode;
61 import org.graalvm.compiler.nodes.calc.AddNode;
62 import org.graalvm.compiler.nodes.calc.ConditionalNode;
63 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
64 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
65 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
66 import org.graalvm.compiler.nodes.calc.IsNullNode;
67 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
68 import org.graalvm.compiler.nodes.calc.NarrowNode;
69 import org.graalvm.compiler.nodes.calc.RightShiftNode;
70 import org.graalvm.compiler.nodes.calc.SignExtendNode;
71 import org.graalvm.compiler.nodes.calc.SubNode;
72 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
73 import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
74 import org.graalvm.compiler.nodes.extended.BoxNode;
75 import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
76 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
77 import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
78 import org.graalvm.compiler.nodes.extended.GuardingNode;
79 import org.graalvm.compiler.nodes.extended.JavaReadNode;
80 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
81 import org.graalvm.compiler.nodes.extended.LoadHubNode;
82 import org.graalvm.compiler.nodes.extended.MembarNode;
83 import org.graalvm.compiler.nodes.extended.RawLoadNode;
84 import org.graalvm.compiler.nodes.extended.RawStoreNode;
85 import org.graalvm.compiler.nodes.extended.UnboxNode;
86 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
87 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
88 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
89 import org.graalvm.compiler.nodes.java.AccessIndexedNode;
90 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
91 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
133 import jdk.vm.ci.code.MemoryBarriers;
134 import jdk.vm.ci.code.TargetDescription;
135 import jdk.vm.ci.meta.DeoptimizationAction;
136 import jdk.vm.ci.meta.DeoptimizationReason;
137 import jdk.vm.ci.meta.JavaConstant;
138 import jdk.vm.ci.meta.JavaKind;
139 import jdk.vm.ci.meta.MetaAccessProvider;
140 import jdk.vm.ci.meta.ResolvedJavaField;
141 import jdk.vm.ci.meta.ResolvedJavaMethod;
142 import jdk.vm.ci.meta.ResolvedJavaType;
143
144 /**
145 * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
146 * implemented by VM-specific subclasses.
147 */
148 public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
149
150 protected final MetaAccessProvider metaAccess;
151 protected final ForeignCallsProvider foreignCalls;
152 protected final TargetDescription target;
153
154 private BoxingSnippets.Templates boxingSnippets;
155 private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
156
157 public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target) {
158 this.metaAccess = metaAccess;
159 this.foreignCalls = foreignCalls;
160 this.target = target;
161 }
162
163 public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
164 boxingSnippets = new BoxingSnippets.Templates(options, factories, factory, providers, snippetReflection, target);
165 indexOfSnippets = new ConstantStringIndexOfSnippets.Templates(options, factories, providers, snippetReflection, target);
166 providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(options, factories, providers, snippetReflection, target));
167 }
168
169 public final TargetDescription getTarget() {
170 return target;
171 }
172
173 @Override
174 public void lower(Node n, LoweringTool tool) {
175 assert n instanceof Lowerable;
176 StructuredGraph graph = (StructuredGraph) n.graph();
177 if (n instanceof LoadFieldNode) {
178 lowerLoadFieldNode((LoadFieldNode) n, tool);
179 } else if (n instanceof StoreFieldNode) {
180 lowerStoreFieldNode((StoreFieldNode) n, tool);
201 } else if (n instanceof UnsafeMemoryStoreNode) {
202 lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
203 } else if (n instanceof JavaReadNode) {
204 lowerJavaReadNode((JavaReadNode) n);
205 } else if (n instanceof JavaWriteNode) {
206 lowerJavaWriteNode((JavaWriteNode) n);
207 } else if (n instanceof CommitAllocationNode) {
208 lowerCommitAllocationNode((CommitAllocationNode) n, tool);
209 } else if (n instanceof BoxNode) {
210 boxingSnippets.lower((BoxNode) n, tool);
211 } else if (n instanceof UnboxNode) {
212 boxingSnippets.lower((UnboxNode) n, tool);
213 } else if (n instanceof VerifyHeapNode) {
214 lowerVerifyHeap((VerifyHeapNode) n);
215 } else if (n instanceof UnaryMathIntrinsicNode) {
216 lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
217 } else if (n instanceof BinaryMathIntrinsicNode) {
218 lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
219 } else if (n instanceof StringIndexOfNode) {
220 lowerIndexOf((StringIndexOfNode) n);
221 } else {
222 throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
223 }
224 }
225
226 private void lowerIndexOf(StringIndexOfNode n) {
227 if (n.getArgument(3).isConstant()) {
228 SnippetLowering lowering = new SnippetLowering() {
229 @Override
230 public void lower(SnippetLowerableMemoryNode node, LoweringTool tool) {
231 if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
232 return;
233 }
234 indexOfSnippets.lower(node, tool);
235 }
236 };
237 SnippetLowerableMemoryNode snippetLower = new SnippetLowerableMemoryNode(lowering, NamedLocationIdentity.getArrayLocation(JavaKind.Char), n.stamp(), n.toArgumentArray());
238 n.graph().add(snippetLower);
239 n.graph().replaceFixedWithFixed(n, snippetLower);
240 }
241 }
242
243 private void lowerBinaryMath(BinaryMathIntrinsicNode math, LoweringTool tool) {
244 if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
245 return;
309 }
310
311 protected void lowerVerifyHeap(VerifyHeapNode n) {
312 GraphUtil.removeFixedWithUnusedInputs(n);
313 }
314
315 protected AddressNode createOffsetAddress(StructuredGraph graph, ValueNode object, long offset) {
316 ValueNode o = ConstantNode.forIntegerKind(target.wordJavaKind, offset, graph);
317 return graph.unique(new OffsetAddressNode(object, o));
318 }
319
320 protected AddressNode createFieldAddress(StructuredGraph graph, ValueNode object, ResolvedJavaField field) {
321 int offset = fieldOffset(field);
322 if (offset >= 0) {
323 return createOffsetAddress(graph, object, offset);
324 } else {
325 return null;
326 }
327 }
328
329 protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
330 assert loadField.getStackKind() != JavaKind.Illegal;
331 StructuredGraph graph = loadField.graph();
332 ResolvedJavaField field = loadField.field();
333 ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
334 object = createNullCheckedValue(object, loadField, tool);
335 Stamp loadStamp = loadStamp(loadField.stamp(), field.getJavaKind());
336
337 AddressNode address = createFieldAddress(graph, object, field);
338 assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
339
340 ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
341 ValueNode readValue = implicitLoadConvert(graph, field.getJavaKind(), memoryRead);
342 loadField.replaceAtUsages(readValue);
343 graph.replaceFixed(loadField, memoryRead);
344
345 if (loadField.isVolatile()) {
346 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
347 graph.addBeforeFixed(memoryRead, preMembar);
348 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
349 graph.addAfterFixed(memoryRead, postMembar);
350 }
351 }
352
353 protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
354 StructuredGraph graph = storeField.graph();
355 ResolvedJavaField field = storeField.field();
356 ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
357 object = createNullCheckedValue(object, storeField, tool);
358 ValueNode value = implicitStoreConvert(graph, storeField.field().getJavaKind(), storeField.value());
359 AddressNode address = createFieldAddress(graph, object, field);
360 assert address != null;
361
362 WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field())));
363 memoryWrite.setStateAfter(storeField.stateAfter());
364 graph.replaceFixedWithFixed(storeField, memoryWrite);
365
366 if (storeField.isVolatile()) {
367 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
368 graph.addBeforeFixed(memoryWrite, preMembar);
369 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
370 graph.addAfterFixed(memoryWrite, postMembar);
371 }
372 }
373
374 /**
375 * Create a PiNode on the index proving that the index is positive. On some platforms this is
376 * important to allow the index to be used as an int in the address mode.
377 */
378 public AddressNode createArrayIndexAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index, GuardingNode boundsCheck) {
634 StructuredGraph graph = read.graph();
635 JavaKind valueKind = read.getReadKind();
636 Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
637
638 ReadNode memoryRead = graph.add(new ReadNode(read.getAddress(), read.getLocationIdentity(), loadStamp, read.getBarrierType()));
639 GuardingNode guard = read.getGuard();
640 ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
641 if (guard == null) {
642 // An unsafe read must not float otherwise it may float above
643 // a test guaranteeing the read is safe.
644 memoryRead.setForceFixed(true);
645 } else {
646 memoryRead.setGuard(guard);
647 }
648 read.replaceAtUsages(readValue);
649 graph.replaceFixed(read, memoryRead);
650 }
651
652 protected void lowerJavaWriteNode(JavaWriteNode write) {
653 StructuredGraph graph = write.graph();
654 JavaKind valueKind = write.getWriteKind();
655 ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
656
657 WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType()));
658 memoryWrite.setStateAfter(write.stateAfter());
659 graph.replaceFixedWithFixed(write, memoryWrite);
660 memoryWrite.setGuard(write.getGuard());
661 }
662
663 protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
664 StructuredGraph graph = commit.graph();
665 if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
666 List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
667
668 ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
669 BitSet omittedValues = new BitSet();
670 int valuePos = 0;
671 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
672 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
673 int entryCount = virtual.entryCount();
674 AbstractNewObjectNode newObject;
675 if (virtual instanceof VirtualInstanceNode) {
676 newObject = graph.add(createNewInstanceFromVirtual(virtual));
901 public abstract int fieldOffset(ResolvedJavaField field);
902
903 public FieldLocationIdentity fieldLocationIdentity(ResolvedJavaField field) {
904 return new FieldLocationIdentity(field);
905 }
906
907 public abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
908
909 public abstract int arrayLengthOffset();
910
911 public abstract int arrayBaseOffset(JavaKind elementKind);
912
913 public int arrayScalingFactor(JavaKind elementKind) {
914 return target.arch.getPlatformKind(elementKind).getSizeInBytes();
915 }
916
917 public Stamp loadStamp(Stamp stamp, JavaKind kind) {
918 return loadStamp(stamp, kind, true);
919 }
920
921 /**
922 * @param compressible whether the stamp should be compressible
923 */
924 protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
925 switch (kind) {
926 case Boolean:
927 case Byte:
928 return IntegerStamp.OPS.getNarrow().foldStamp(32, 8, stamp);
929 case Char:
930 case Short:
931 return IntegerStamp.OPS.getNarrow().foldStamp(32, 16, stamp);
932 }
933 return stamp;
934 }
935
936 public final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
937 return implicitLoadConvert(graph, kind, value, true);
938 }
939
940 public ValueNode implicitLoadConvert(JavaKind kind, ValueNode value) {
941 return implicitLoadConvert(kind, value, true);
942 }
943
944 protected final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
945 ValueNode ret = implicitLoadConvert(kind, value, compressible);
946 if (!ret.isAlive()) {
947 ret = graph.addOrUnique(ret);
948 }
949 return ret;
950 }
951
952 /**
953 * @param compressible whether the covert should be compressible
954 */
955 protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
956 switch (kind) {
957 case Byte:
958 case Short:
959 return new SignExtendNode(value, 32);
960 case Boolean:
961 case Char:
962 return new ZeroExtendNode(value, 32);
963 }
964 return value;
965 }
966
967 public final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
968 return implicitStoreConvert(graph, kind, value, true);
969 }
970
971 public ValueNode implicitStoreConvert(JavaKind kind, ValueNode value) {
972 return implicitStoreConvert(kind, value, true);
973 }
974
975 protected final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
976 ValueNode ret = implicitStoreConvert(kind, value, compressible);
977 if (!ret.isAlive()) {
978 ret = graph.addOrUnique(ret);
979 }
980 return ret;
981 }
982
983 /**
984 * @param compressible whether the covert should be compressible
985 */
986 protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
987 switch (kind) {
988 case Boolean:
989 case Byte:
990 return new NarrowNode(value, 8);
991 case Char:
992 case Short:
993 return new NarrowNode(value, 16);
994 }
995 return value;
996 }
997
998 protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool);
999
1000 protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
1001
1002 protected GuardingNode getBoundsCheck(AccessIndexedNode n, ValueNode array, LoweringTool tool) {
1003 StructuredGraph graph = n.graph();
1004 ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
1005 if (arrayLength == null) {
1006 arrayLength = createReadArrayLength(array, n, tool);
1007 } else {
1008 arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
1009 }
1010
1011 LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength);
1012 if (boundsCheck.isTautology()) {
1013 return null;
1014 } else {
1015 return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile);
1016 }
1017 }
1018
1019 protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
1020 if (StampTool.isPointerNonNull(object)) {
1021 return null;
1022 }
1023 return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true);
1024 }
1025
1026 protected ValueNode createNullCheckedValue(ValueNode object, FixedNode before, LoweringTool tool) {
1027 GuardingNode nullCheck = createNullCheck(object, before, tool);
1028 if (nullCheck == null) {
1029 return object;
1030 } else {
1031 return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck));
1032 }
1033 }
1034
1035 @Override
1036 public ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address) {
1037 StructuredGraph graph = address.graph();
1038 ValueNode offset = ((OffsetAddressNode) address).getOffset();
1039
1040 int base = arrayBaseOffset(elementKind);
1041 ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), base, graph)));
1042
1043 int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
1044 ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph)));
1045 return IntegerConvertNode.convert(ret, StampFactory.forKind(JavaKind.Int), graph);
1046 }
1047 }
|
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 package org.graalvm.compiler.replacements;
24
25 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
26 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
27 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
28 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
29 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
30 import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException;
31 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
32 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
33 import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
34 import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull;
35
36 import java.nio.ByteOrder;
37 import java.util.ArrayList;
38 import java.util.BitSet;
39 import java.util.List;
40
41 import org.graalvm.compiler.api.directives.GraalDirectives;
42 import org.graalvm.compiler.api.replacements.Snippet;
43 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
44 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
45 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
46 import org.graalvm.compiler.core.common.type.IntegerStamp;
47 import org.graalvm.compiler.core.common.type.ObjectStamp;
48 import org.graalvm.compiler.core.common.type.Stamp;
49 import org.graalvm.compiler.core.common.type.StampFactory;
50 import org.graalvm.compiler.core.common.type.TypeReference;
51 import org.graalvm.compiler.debug.DebugHandlersFactory;
52 import org.graalvm.compiler.debug.GraalError;
53 import org.graalvm.compiler.graph.Node;
54 import org.graalvm.compiler.nodeinfo.InputType;
55 import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
56 import org.graalvm.compiler.nodes.ConstantNode;
57 import org.graalvm.compiler.nodes.FieldLocationIdentity;
58 import org.graalvm.compiler.nodes.FixedNode;
59 import org.graalvm.compiler.nodes.LogicNode;
60 import org.graalvm.compiler.nodes.NamedLocationIdentity;
61 import org.graalvm.compiler.nodes.PiNode;
62 import org.graalvm.compiler.nodes.StructuredGraph;
63 import org.graalvm.compiler.nodes.ValueNode;
64 import org.graalvm.compiler.nodes.calc.AddNode;
65 import org.graalvm.compiler.nodes.calc.ConditionalNode;
66 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
67 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
68 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
69 import org.graalvm.compiler.nodes.calc.IsNullNode;
70 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
71 import org.graalvm.compiler.nodes.calc.NarrowNode;
72 import org.graalvm.compiler.nodes.calc.RightShiftNode;
73 import org.graalvm.compiler.nodes.calc.SignExtendNode;
74 import org.graalvm.compiler.nodes.calc.SubNode;
75 import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
76 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
77 import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
78 import org.graalvm.compiler.nodes.extended.BoxNode;
79 import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
80 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
81 import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
82 import org.graalvm.compiler.nodes.extended.GuardingNode;
83 import org.graalvm.compiler.nodes.extended.JavaReadNode;
84 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
85 import org.graalvm.compiler.nodes.extended.LoadHubNode;
86 import org.graalvm.compiler.nodes.extended.MembarNode;
87 import org.graalvm.compiler.nodes.extended.RawLoadNode;
88 import org.graalvm.compiler.nodes.extended.RawStoreNode;
89 import org.graalvm.compiler.nodes.extended.UnboxNode;
90 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
91 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
92 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
93 import org.graalvm.compiler.nodes.java.AccessIndexedNode;
94 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
95 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
137 import jdk.vm.ci.code.MemoryBarriers;
138 import jdk.vm.ci.code.TargetDescription;
139 import jdk.vm.ci.meta.DeoptimizationAction;
140 import jdk.vm.ci.meta.DeoptimizationReason;
141 import jdk.vm.ci.meta.JavaConstant;
142 import jdk.vm.ci.meta.JavaKind;
143 import jdk.vm.ci.meta.MetaAccessProvider;
144 import jdk.vm.ci.meta.ResolvedJavaField;
145 import jdk.vm.ci.meta.ResolvedJavaMethod;
146 import jdk.vm.ci.meta.ResolvedJavaType;
147
148 /**
149 * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
150 * implemented by VM-specific subclasses.
151 */
152 public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
153
154 protected final MetaAccessProvider metaAccess;
155 protected final ForeignCallsProvider foreignCalls;
156 protected final TargetDescription target;
157 private final boolean useCompressedOops;
158
159 private BoxingSnippets.Templates boxingSnippets;
160 private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
161
162 public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target, boolean useCompressedOops) {
163 this.metaAccess = metaAccess;
164 this.foreignCalls = foreignCalls;
165 this.target = target;
166 this.useCompressedOops = useCompressedOops;
167 }
168
169 public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
170 boxingSnippets = new BoxingSnippets.Templates(options, factories, factory, providers, snippetReflection, target);
171 indexOfSnippets = new ConstantStringIndexOfSnippets.Templates(options, factories, providers, snippetReflection, target);
172 providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(options, factories, providers, snippetReflection, target));
173 }
174
175 public final TargetDescription getTarget() {
176 return target;
177 }
178
179 @Override
180 public void lower(Node n, LoweringTool tool) {
181 assert n instanceof Lowerable;
182 StructuredGraph graph = (StructuredGraph) n.graph();
183 if (n instanceof LoadFieldNode) {
184 lowerLoadFieldNode((LoadFieldNode) n, tool);
185 } else if (n instanceof StoreFieldNode) {
186 lowerStoreFieldNode((StoreFieldNode) n, tool);
207 } else if (n instanceof UnsafeMemoryStoreNode) {
208 lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
209 } else if (n instanceof JavaReadNode) {
210 lowerJavaReadNode((JavaReadNode) n);
211 } else if (n instanceof JavaWriteNode) {
212 lowerJavaWriteNode((JavaWriteNode) n);
213 } else if (n instanceof CommitAllocationNode) {
214 lowerCommitAllocationNode((CommitAllocationNode) n, tool);
215 } else if (n instanceof BoxNode) {
216 boxingSnippets.lower((BoxNode) n, tool);
217 } else if (n instanceof UnboxNode) {
218 boxingSnippets.lower((UnboxNode) n, tool);
219 } else if (n instanceof VerifyHeapNode) {
220 lowerVerifyHeap((VerifyHeapNode) n);
221 } else if (n instanceof UnaryMathIntrinsicNode) {
222 lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
223 } else if (n instanceof BinaryMathIntrinsicNode) {
224 lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
225 } else if (n instanceof StringIndexOfNode) {
226 lowerIndexOf((StringIndexOfNode) n);
227 } else if (n instanceof UnpackEndianHalfNode) {
228 lowerSecondHalf((UnpackEndianHalfNode) n);
229 } else {
230 throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
231 }
232 }
233
234 private void lowerSecondHalf(UnpackEndianHalfNode n) {
235 ByteOrder byteOrder = target.arch.getByteOrder();
236 n.lower(byteOrder);
237 }
238
239 private void lowerIndexOf(StringIndexOfNode n) {
240 if (n.getArgument(3).isConstant()) {
241 SnippetLowering lowering = new SnippetLowering() {
242 @Override
243 public void lower(SnippetLowerableMemoryNode node, LoweringTool tool) {
244 if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
245 return;
246 }
247 indexOfSnippets.lower(node, tool);
248 }
249 };
250 SnippetLowerableMemoryNode snippetLower = new SnippetLowerableMemoryNode(lowering, NamedLocationIdentity.getArrayLocation(JavaKind.Char), n.stamp(), n.toArgumentArray());
251 n.graph().add(snippetLower);
252 n.graph().replaceFixedWithFixed(n, snippetLower);
253 }
254 }
255
256 private void lowerBinaryMath(BinaryMathIntrinsicNode math, LoweringTool tool) {
257 if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
258 return;
322 }
323
324 protected void lowerVerifyHeap(VerifyHeapNode n) {
325 GraphUtil.removeFixedWithUnusedInputs(n);
326 }
327
328 protected AddressNode createOffsetAddress(StructuredGraph graph, ValueNode object, long offset) {
329 ValueNode o = ConstantNode.forIntegerKind(target.wordJavaKind, offset, graph);
330 return graph.unique(new OffsetAddressNode(object, o));
331 }
332
333 protected AddressNode createFieldAddress(StructuredGraph graph, ValueNode object, ResolvedJavaField field) {
334 int offset = fieldOffset(field);
335 if (offset >= 0) {
336 return createOffsetAddress(graph, object, offset);
337 } else {
338 return null;
339 }
340 }
341
342 protected abstract JavaKind getStorageKind(ResolvedJavaField field);
343
344 protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
345 assert loadField.getStackKind() != JavaKind.Illegal;
346 StructuredGraph graph = loadField.graph();
347 ResolvedJavaField field = loadField.field();
348 ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
349 object = createNullCheckedValue(object, loadField, tool);
350 Stamp loadStamp = loadStamp(loadField.stamp(), getStorageKind(field));
351
352 AddressNode address = createFieldAddress(graph, object, field);
353 assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
354
355 ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
356 ValueNode readValue = implicitLoadConvert(graph, getStorageKind(field), memoryRead);
357 loadField.replaceAtUsages(readValue);
358 graph.replaceFixed(loadField, memoryRead);
359
360 if (loadField.isVolatile()) {
361 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
362 graph.addBeforeFixed(memoryRead, preMembar);
363 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
364 graph.addAfterFixed(memoryRead, postMembar);
365 }
366 }
367
368 protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
369 StructuredGraph graph = storeField.graph();
370 ResolvedJavaField field = storeField.field();
371 ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
372 object = createNullCheckedValue(object, storeField, tool);
373 ValueNode value = implicitStoreConvert(graph, getStorageKind(storeField.field()), storeField.value());
374 AddressNode address = createFieldAddress(graph, object, field);
375 assert address != null;
376
377 WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field())));
378 memoryWrite.setStateAfter(storeField.stateAfter());
379 graph.replaceFixedWithFixed(storeField, memoryWrite);
380
381 if (storeField.isVolatile()) {
382 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
383 graph.addBeforeFixed(memoryWrite, preMembar);
384 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
385 graph.addAfterFixed(memoryWrite, postMembar);
386 }
387 }
388
389 /**
390 * Create a PiNode on the index proving that the index is positive. On some platforms this is
391 * important to allow the index to be used as an int in the address mode.
392 */
393 public AddressNode createArrayIndexAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index, GuardingNode boundsCheck) {
649 StructuredGraph graph = read.graph();
650 JavaKind valueKind = read.getReadKind();
651 Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
652
653 ReadNode memoryRead = graph.add(new ReadNode(read.getAddress(), read.getLocationIdentity(), loadStamp, read.getBarrierType()));
654 GuardingNode guard = read.getGuard();
655 ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
656 if (guard == null) {
657 // An unsafe read must not float otherwise it may float above
658 // a test guaranteeing the read is safe.
659 memoryRead.setForceFixed(true);
660 } else {
661 memoryRead.setGuard(guard);
662 }
663 read.replaceAtUsages(readValue);
664 graph.replaceFixed(read, memoryRead);
665 }
666
667 protected void lowerJavaWriteNode(JavaWriteNode write) {
668 StructuredGraph graph = write.graph();
669 ValueNode value = implicitStoreConvert(graph, write.getWriteKind(), write.value(), write.isCompressible());
670 WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType()));
671 memoryWrite.setStateAfter(write.stateAfter());
672 graph.replaceFixedWithFixed(write, memoryWrite);
673 memoryWrite.setGuard(write.getGuard());
674 }
675
676 protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
677 StructuredGraph graph = commit.graph();
678 if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
679 List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
680
681 ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
682 BitSet omittedValues = new BitSet();
683 int valuePos = 0;
684 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
685 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
686 int entryCount = virtual.entryCount();
687 AbstractNewObjectNode newObject;
688 if (virtual instanceof VirtualInstanceNode) {
689 newObject = graph.add(createNewInstanceFromVirtual(virtual));
914 public abstract int fieldOffset(ResolvedJavaField field);
915
916 public FieldLocationIdentity fieldLocationIdentity(ResolvedJavaField field) {
917 return new FieldLocationIdentity(field);
918 }
919
920 public abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
921
922 public abstract int arrayLengthOffset();
923
924 public abstract int arrayBaseOffset(JavaKind elementKind);
925
926 public int arrayScalingFactor(JavaKind elementKind) {
927 return target.arch.getPlatformKind(elementKind).getSizeInBytes();
928 }
929
930 public Stamp loadStamp(Stamp stamp, JavaKind kind) {
931 return loadStamp(stamp, kind, true);
932 }
933
934 private boolean useCompressedOops(JavaKind kind, boolean compressible) {
935 return kind == JavaKind.Object && compressible && useCompressedOops;
936 }
937
938 protected abstract Stamp loadCompressedStamp(ObjectStamp stamp);
939
940 /**
941 * @param compressible whether the stamp should be compressible
942 */
943 protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
944 if (useCompressedOops(kind, compressible)) {
945 return loadCompressedStamp((ObjectStamp) stamp);
946 }
947
948 switch (kind) {
949 case Boolean:
950 case Byte:
951 return IntegerStamp.OPS.getNarrow().foldStamp(32, 8, stamp);
952 case Char:
953 case Short:
954 return IntegerStamp.OPS.getNarrow().foldStamp(32, 16, stamp);
955 }
956 return stamp;
957 }
958
959 public final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
960 return implicitLoadConvert(graph, kind, value, true);
961 }
962
963 public ValueNode implicitLoadConvert(JavaKind kind, ValueNode value) {
964 return implicitLoadConvert(kind, value, true);
965 }
966
967 protected final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
968 ValueNode ret = implicitLoadConvert(kind, value, compressible);
969 if (!ret.isAlive()) {
970 ret = graph.addOrUnique(ret);
971 }
972 return ret;
973 }
974
975 protected abstract ValueNode newCompressionNode(CompressionOp op, ValueNode value);
976
977 /**
978 * @param compressible whether the convert should be compressible
979 */
980 protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
981 if (useCompressedOops(kind, compressible)) {
982 return newCompressionNode(CompressionOp.Uncompress, value);
983 }
984
985 switch (kind) {
986 case Byte:
987 case Short:
988 return new SignExtendNode(value, 32);
989 case Boolean:
990 case Char:
991 return new ZeroExtendNode(value, 32);
992 }
993 return value;
994 }
995
996 public final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
997 return implicitStoreConvert(graph, kind, value, true);
998 }
999
1000 public ValueNode implicitStoreConvert(JavaKind kind, ValueNode value) {
1001 return implicitStoreConvert(kind, value, true);
1002 }
1003
1004 protected final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
1005 ValueNode ret = implicitStoreConvert(kind, value, compressible);
1006 if (!ret.isAlive()) {
1007 ret = graph.addOrUnique(ret);
1008 }
1009 return ret;
1010 }
1011
1012 /**
1013 * @param compressible whether the covert should be compressible
1014 */
1015 protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
1016 if (useCompressedOops(kind, compressible)) {
1017 return newCompressionNode(CompressionOp.Compress, value);
1018 }
1019
1020 switch (kind) {
1021 case Boolean:
1022 case Byte:
1023 return new NarrowNode(value, 8);
1024 case Char:
1025 case Short:
1026 return new NarrowNode(value, 16);
1027 }
1028 return value;
1029 }
1030
1031 protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool);
1032
1033 protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
1034
1035 protected GuardingNode getBoundsCheck(AccessIndexedNode n, ValueNode array, LoweringTool tool) {
1036 StructuredGraph graph = n.graph();
1037 ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
1038 if (arrayLength == null) {
1039 arrayLength = createReadArrayLength(array, n, tool);
1040 } else {
1041 arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
1042 }
1043
1044 LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength);
1045 if (boundsCheck.isTautology()) {
1046 return null;
1047 }
1048 return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile);
1049 }
1050
1051 protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
1052 if (StampTool.isPointerNonNull(object)) {
1053 return null;
1054 }
1055 return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true);
1056 }
1057
1058 protected ValueNode createNullCheckedValue(ValueNode object, FixedNode before, LoweringTool tool) {
1059 GuardingNode nullCheck = createNullCheck(object, before, tool);
1060 if (nullCheck == null) {
1061 return object;
1062 }
1063 return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck));
1064 }
1065
1066 @Override
1067 public ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address) {
1068 StructuredGraph graph = address.graph();
1069 ValueNode offset = ((OffsetAddressNode) address).getOffset();
1070
1071 int base = arrayBaseOffset(elementKind);
1072 ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), base, graph)));
1073
1074 int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
1075 ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph)));
1076 return IntegerConvertNode.convert(ret, StampFactory.forKind(JavaKind.Int), graph);
1077 }
1078 }
|