DefaultJavaLoweringProvider.java revision 13482:6d53d0ae27e5
1/*
2 * Copyright (c) 2011, 2016, 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 */
23package org.graalvm.compiler.replacements;
24
25import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
26import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
27import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
28import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
29import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
30import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException;
31import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
32import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
33import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
34import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull;
35
36import java.util.ArrayList;
37import java.util.BitSet;
38import java.util.List;
39
40import org.graalvm.compiler.api.directives.GraalDirectives;
41import org.graalvm.compiler.api.replacements.Snippet;
42import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
43import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
44import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
45import org.graalvm.compiler.core.common.type.IntegerStamp;
46import org.graalvm.compiler.core.common.type.Stamp;
47import org.graalvm.compiler.core.common.type.StampFactory;
48import org.graalvm.compiler.core.common.type.TypeReference;
49import org.graalvm.compiler.debug.DebugHandlersFactory;
50import org.graalvm.compiler.debug.GraalError;
51import org.graalvm.compiler.graph.Node;
52import org.graalvm.compiler.nodeinfo.InputType;
53import org.graalvm.compiler.nodes.ConstantNode;
54import org.graalvm.compiler.nodes.FieldLocationIdentity;
55import org.graalvm.compiler.nodes.FixedNode;
56import org.graalvm.compiler.nodes.LogicNode;
57import org.graalvm.compiler.nodes.NamedLocationIdentity;
58import org.graalvm.compiler.nodes.PiNode;
59import org.graalvm.compiler.nodes.StructuredGraph;
60import org.graalvm.compiler.nodes.ValueNode;
61import org.graalvm.compiler.nodes.calc.AddNode;
62import org.graalvm.compiler.nodes.calc.ConditionalNode;
63import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
64import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
65import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
66import org.graalvm.compiler.nodes.calc.IsNullNode;
67import org.graalvm.compiler.nodes.calc.LeftShiftNode;
68import org.graalvm.compiler.nodes.calc.NarrowNode;
69import org.graalvm.compiler.nodes.calc.RightShiftNode;
70import org.graalvm.compiler.nodes.calc.SignExtendNode;
71import org.graalvm.compiler.nodes.calc.SubNode;
72import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
73import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
74import org.graalvm.compiler.nodes.extended.BoxNode;
75import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
76import org.graalvm.compiler.nodes.extended.ForeignCallNode;
77import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
78import org.graalvm.compiler.nodes.extended.GuardingNode;
79import org.graalvm.compiler.nodes.extended.JavaReadNode;
80import org.graalvm.compiler.nodes.extended.JavaWriteNode;
81import org.graalvm.compiler.nodes.extended.LoadHubNode;
82import org.graalvm.compiler.nodes.extended.MembarNode;
83import org.graalvm.compiler.nodes.extended.RawLoadNode;
84import org.graalvm.compiler.nodes.extended.RawStoreNode;
85import org.graalvm.compiler.nodes.extended.UnboxNode;
86import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
87import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
88import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
89import org.graalvm.compiler.nodes.java.AccessIndexedNode;
90import org.graalvm.compiler.nodes.java.ArrayLengthNode;
91import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
92import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode;
93import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
94import org.graalvm.compiler.nodes.java.InstanceOfNode;
95import org.graalvm.compiler.nodes.java.LoadFieldNode;
96import org.graalvm.compiler.nodes.java.LoadIndexedNode;
97import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
98import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
99import org.graalvm.compiler.nodes.java.MonitorEnterNode;
100import org.graalvm.compiler.nodes.java.MonitorIdNode;
101import org.graalvm.compiler.nodes.java.NewArrayNode;
102import org.graalvm.compiler.nodes.java.NewInstanceNode;
103import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
104import org.graalvm.compiler.nodes.java.StoreFieldNode;
105import org.graalvm.compiler.nodes.java.StoreIndexedNode;
106import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
107import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
108import org.graalvm.compiler.nodes.memory.ReadNode;
109import org.graalvm.compiler.nodes.memory.WriteNode;
110import org.graalvm.compiler.nodes.memory.address.AddressNode;
111import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
112import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
113import org.graalvm.compiler.nodes.spi.Lowerable;
114import org.graalvm.compiler.nodes.spi.LoweringProvider;
115import org.graalvm.compiler.nodes.spi.LoweringTool;
116import org.graalvm.compiler.nodes.type.StampTool;
117import org.graalvm.compiler.nodes.util.GraphUtil;
118import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
119import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
120import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
121import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
122import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
123import org.graalvm.compiler.options.OptionValues;
124import org.graalvm.compiler.phases.util.Providers;
125import org.graalvm.compiler.replacements.SnippetLowerableMemoryNode.SnippetLowering;
126import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
127import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
128import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
129import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
130import org.graalvm.word.LocationIdentity;
131
132import jdk.vm.ci.code.CodeUtil;
133import jdk.vm.ci.code.MemoryBarriers;
134import jdk.vm.ci.code.TargetDescription;
135import jdk.vm.ci.meta.DeoptimizationAction;
136import jdk.vm.ci.meta.DeoptimizationReason;
137import jdk.vm.ci.meta.JavaConstant;
138import jdk.vm.ci.meta.JavaKind;
139import jdk.vm.ci.meta.MetaAccessProvider;
140import jdk.vm.ci.meta.ResolvedJavaField;
141import jdk.vm.ci.meta.ResolvedJavaMethod;
142import 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 */
148public 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);
181        } else if (n instanceof LoadIndexedNode) {
182            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
183        } else if (n instanceof StoreIndexedNode) {
184            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
185        } else if (n instanceof ArrayLengthNode) {
186            lowerArrayLengthNode((ArrayLengthNode) n, tool);
187        } else if (n instanceof LoadHubNode) {
188            lowerLoadHubNode((LoadHubNode) n, tool);
189        } else if (n instanceof MonitorEnterNode) {
190            lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
191        } else if (n instanceof UnsafeCompareAndSwapNode) {
192            lowerCompareAndSwapNode((UnsafeCompareAndSwapNode) n);
193        } else if (n instanceof AtomicReadAndWriteNode) {
194            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
195        } else if (n instanceof RawLoadNode) {
196            lowerUnsafeLoadNode((RawLoadNode) n, tool);
197        } else if (n instanceof UnsafeMemoryLoadNode) {
198            lowerUnsafeMemoryLoadNode((UnsafeMemoryLoadNode) n);
199        } else if (n instanceof RawStoreNode) {
200            lowerUnsafeStoreNode((RawStoreNode) n);
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;
246        }
247        ResolvedJavaMethod method = math.graph().method();
248        if (method != null) {
249            if (method.getAnnotation(Snippet.class) != null) {
250                /*
251                 * In the context of the snippet use the LIR lowering instead of the Node lowering.
252                 */
253                return;
254            }
255            if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
256                /*
257                 * A root compilation of the intrinsic method should emit the full assembly
258                 * implementation.
259                 */
260                return;
261            }
262
263        }
264        ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
265        if (foreignCall != null) {
266            StructuredGraph graph = math.graph();
267            ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, toForeignCall(math.getOperation()), math.getX(), math.getY()));
268            graph.addAfterFixed(tool.lastFixedNode(), call);
269            math.replaceAtUsages(call);
270        }
271    }
272
273    private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) {
274        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
275            return;
276        }
277        ResolvedJavaMethod method = math.graph().method();
278        if (method != null) {
279            if (method.getAnnotation(Snippet.class) != null) {
280                /*
281                 * In the context of the snippet use the LIR lowering instead of the Node lowering.
282                 */
283                return;
284            }
285            if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
286                /*
287                 * A root compilation of the intrinsic method should emit the full assembly
288                 * implementation.
289                 */
290                return;
291            }
292
293        }
294        ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
295        if (foreignCall != null) {
296            StructuredGraph graph = math.graph();
297            ForeignCallNode call = math.graph().add(new ForeignCallNode(foreignCalls, foreignCall, math.getValue()));
298            graph.addAfterFixed(tool.lastFixedNode(), call);
299            math.replaceAtUsages(call);
300        }
301    }
302
303    protected ForeignCallDescriptor toForeignCall(UnaryOperation operation) {
304        return operation.foreignCallDescriptor;
305    }
306
307    protected ForeignCallDescriptor toForeignCall(BinaryOperation operation) {
308        return operation.foreignCallDescriptor;
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) {
379        IntegerStamp indexStamp = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1);
380        ValueNode positiveIndex = graph.maybeAddOrUnique(PiNode.create(index, indexStamp, boundsCheck != null ? boundsCheck.asNode() : null));
381        return createArrayAddress(graph, array, elementKind, positiveIndex);
382    }
383
384    public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index) {
385        ValueNode wordIndex;
386        if (target.wordSize > 4) {
387            wordIndex = graph.unique(new SignExtendNode(index, target.wordSize * 8));
388        } else {
389            assert target.wordSize == 4 : "unsupported word size";
390            wordIndex = index;
391        }
392
393        int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
394        ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph)));
395
396        int base = arrayBaseOffset(elementKind);
397        ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordJavaKind, base, graph)));
398
399        return graph.unique(new OffsetAddressNode(array, offset));
400    }
401
402    protected void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
403        StructuredGraph graph = loadIndexed.graph();
404        ValueNode array = loadIndexed.array();
405        array = createNullCheckedValue(array, loadIndexed, tool);
406        JavaKind elementKind = loadIndexed.elementKind();
407        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
408
409        GuardingNode boundsCheck = getBoundsCheck(loadIndexed, array, tool);
410        AddressNode address = createArrayIndexAddress(graph, array, elementKind, loadIndexed.index(), boundsCheck);
411        ReadNode memoryRead = graph.add(new ReadNode(address, NamedLocationIdentity.getArrayLocation(elementKind), loadStamp, BarrierType.NONE));
412        memoryRead.setGuard(boundsCheck);
413        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
414
415        loadIndexed.replaceAtUsages(readValue);
416        graph.replaceFixed(loadIndexed, memoryRead);
417    }
418
419    protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
420        StructuredGraph graph = storeIndexed.graph();
421
422        ValueNode value = storeIndexed.value();
423        ValueNode array = storeIndexed.array();
424
425        array = this.createNullCheckedValue(array, storeIndexed, tool);
426
427        GuardingNode boundsCheck = getBoundsCheck(storeIndexed, array, tool);
428
429        JavaKind elementKind = storeIndexed.elementKind();
430
431        LogicNode condition = null;
432        if (elementKind == JavaKind.Object && !StampTool.isPointerAlwaysNull(value)) {
433            /* Array store check. */
434            TypeReference arrayType = StampTool.typeReferenceOrNull(array);
435            if (arrayType != null && arrayType.isExact()) {
436                ResolvedJavaType elementType = arrayType.getType().getComponentType();
437                if (!elementType.isJavaLangObject()) {
438                    TypeReference typeReference = TypeReference.createTrusted(storeIndexed.graph().getAssumptions(), elementType);
439                    LogicNode typeTest = graph.addOrUniqueWithInputs(InstanceOfNode.create(typeReference, value));
440                    condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
441                }
442            } else {
443                /*
444                 * The guard on the read hub should be the null check of the array that was
445                 * introduced earlier.
446                 */
447                ValueNode arrayClass = createReadHub(graph, array, tool);
448                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
449                LogicNode typeTest = graph.unique(InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), componentHub, value, false));
450                condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
451            }
452        }
453
454        AddressNode address = createArrayIndexAddress(graph, array, elementKind, storeIndexed.index(), boundsCheck);
455        WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
456                        arrayStoreBarrierType(storeIndexed.elementKind())));
457        memoryWrite.setGuard(boundsCheck);
458        if (condition != null) {
459            tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile);
460        }
461        memoryWrite.setStateAfter(storeIndexed.stateAfter());
462        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
463    }
464
465    protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
466        arrayLengthNode.replaceAtUsages(createReadArrayLength(arrayLengthNode.array(), arrayLengthNode, tool));
467        StructuredGraph graph = arrayLengthNode.graph();
468        graph.removeFixed(arrayLengthNode);
469    }
470
471    /**
472     * Creates a read node that read the array length and is guarded by a null-check.
473     *
474     * The created node is placed before {@code before} in the CFG.
475     */
476    protected ReadNode createReadArrayLength(ValueNode array, FixedNode before, LoweringTool tool) {
477        StructuredGraph graph = array.graph();
478        ValueNode canonicalArray = this.createNullCheckedValue(skipPiWhileNonNull(array), before, tool);
479        AddressNode address = createOffsetAddress(graph, canonicalArray, arrayLengthOffset());
480        ReadNode readArrayLength = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, StampFactory.positiveInt(), BarrierType.NONE));
481        graph.addBeforeFixed(before, readArrayLength);
482        return readArrayLength;
483    }
484
485    protected void lowerLoadHubNode(LoadHubNode loadHub, LoweringTool tool) {
486        StructuredGraph graph = loadHub.graph();
487        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
488            return;
489        }
490        if (graph.getGuardsStage().allowsFloatingGuards()) {
491            return;
492        }
493        ValueNode hub = createReadHub(graph, loadHub.getValue(), tool);
494        loadHub.replaceAtUsagesAndDelete(hub);
495    }
496
497    protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
498        ValueNode object = createNullCheckedValue(monitorEnter.object(), monitorEnter, tool);
499        ValueNode hub = graph.addOrUnique(LoadHubNode.create(object, tool.getStampProvider(), tool.getMetaAccess(), tool.getConstantReflection()));
500        RawMonitorEnterNode rawMonitorEnter = graph.add(new RawMonitorEnterNode(object, hub, monitorEnter.getMonitorId()));
501        rawMonitorEnter.setStateBefore(monitorEnter.stateBefore());
502        rawMonitorEnter.setStateAfter(monitorEnter.stateAfter());
503        graph.replaceFixedWithFixed(monitorEnter, rawMonitorEnter);
504    }
505
506    protected void lowerCompareAndSwapNode(UnsafeCompareAndSwapNode cas) {
507        StructuredGraph graph = cas.graph();
508        JavaKind valueKind = cas.getValueKind();
509
510        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
511        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
512
513        AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
514        LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, compareAndSwapBarrierType(cas)));
515        atomicNode.setStateAfter(cas.stateAfter());
516        graph.replaceFixedWithFixed(cas, atomicNode);
517    }
518
519    protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
520        StructuredGraph graph = n.graph();
521        JavaKind valueKind = n.getValueKind();
522
523        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
524
525        AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
526        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, atomicReadAndWriteBarrierType(n)));
527        memoryRead.setStateAfter(n.stateAfter());
528
529        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
530        n.stateAfter().replaceFirstInput(n, memoryRead);
531        n.replaceAtUsages(readValue);
532        graph.replaceFixedWithFixed(n, memoryRead);
533    }
534
535    /**
536     * @param tool utility for performing the lowering
537     */
538    protected void lowerUnsafeLoadNode(RawLoadNode load, LoweringTool tool) {
539        StructuredGraph graph = load.graph();
540        if (load instanceof GuardedUnsafeLoadNode) {
541            GuardedUnsafeLoadNode guardedLoad = (GuardedUnsafeLoadNode) load;
542            GuardingNode guard = guardedLoad.getGuard();
543            if (guard == null) {
544                // can float freely if the guard folded away
545                ReadNode memoryRead = createUnsafeRead(graph, load, null);
546                memoryRead.setForceFixed(false);
547                graph.replaceFixedWithFixed(load, memoryRead);
548            } else {
549                // must be guarded, but flows below the guard
550                ReadNode memoryRead = createUnsafeRead(graph, load, guard);
551                graph.replaceFixedWithFixed(load, memoryRead);
552            }
553        } else {
554            // never had a guarding condition so it must be fixed, creation of the read will force
555            // it to be fixed
556            ReadNode memoryRead = createUnsafeRead(graph, load, null);
557            graph.replaceFixedWithFixed(load, memoryRead);
558        }
559    }
560
561    protected AddressNode createUnsafeAddress(StructuredGraph graph, ValueNode object, ValueNode offset) {
562        if (object.isConstant() && object.asConstant().isDefaultForKind()) {
563            return graph.unique(new RawAddressNode(offset));
564        } else {
565            return graph.unique(new OffsetAddressNode(object, offset));
566        }
567    }
568
569    protected ReadNode createUnsafeRead(StructuredGraph graph, RawLoadNode load, GuardingNode guard) {
570        boolean compressible = load.accessKind() == JavaKind.Object;
571        JavaKind readKind = load.accessKind();
572        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
573        AddressNode address = createUnsafeAddress(graph, load.object(), load.offset());
574        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
575        if (guard == null) {
576            // An unsafe read must not float otherwise it may float above
577            // a test guaranteeing the read is safe.
578            memoryRead.setForceFixed(true);
579        } else {
580            memoryRead.setGuard(guard);
581        }
582        ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, compressible), readKind);
583        load.replaceAtUsages(readValue);
584        return memoryRead;
585    }
586
587    protected void lowerUnsafeMemoryLoadNode(UnsafeMemoryLoadNode load) {
588        StructuredGraph graph = load.graph();
589        JavaKind readKind = load.getKind();
590        assert readKind != JavaKind.Object;
591        Stamp loadStamp = loadStamp(load.stamp(), readKind, false);
592        AddressNode address = graph.unique(new RawAddressNode(load.getAddress()));
593        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
594        // An unsafe read must not float otherwise it may float above
595        // a test guaranteeing the read is safe.
596        memoryRead.setForceFixed(true);
597        ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, false), readKind);
598        load.replaceAtUsages(readValue);
599        graph.replaceFixedWithFixed(load, memoryRead);
600    }
601
602    private static ValueNode performBooleanCoercionIfNecessary(ValueNode readValue, JavaKind readKind) {
603        if (readKind == JavaKind.Boolean) {
604            StructuredGraph graph = readValue.graph();
605            IntegerEqualsNode eq = graph.addOrUnique(new IntegerEqualsNode(readValue, ConstantNode.forInt(0, graph)));
606            return graph.addOrUnique(new ConditionalNode(eq, ConstantNode.forBoolean(false, graph), ConstantNode.forBoolean(true, graph)));
607        }
608        return readValue;
609    }
610
611    protected void lowerUnsafeStoreNode(RawStoreNode store) {
612        StructuredGraph graph = store.graph();
613        boolean compressible = store.value().getStackKind() == JavaKind.Object;
614        JavaKind valueKind = store.accessKind();
615        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
616        AddressNode address = createUnsafeAddress(graph, store.object(), store.offset());
617        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, unsafeStoreBarrierType(store)));
618        write.setStateAfter(store.stateAfter());
619        graph.replaceFixedWithFixed(store, write);
620    }
621
622    protected void lowerUnsafeMemoryStoreNode(UnsafeMemoryStoreNode store) {
623        StructuredGraph graph = store.graph();
624        assert store.getValue().getStackKind() != JavaKind.Object;
625        JavaKind valueKind = store.getKind();
626        ValueNode value = implicitStoreConvert(graph, valueKind, store.getValue(), false);
627        AddressNode address = graph.unique(new RawAddressNode(store.getAddress()));
628        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, BarrierType.NONE));
629        write.setStateAfter(store.stateAfter());
630        graph.replaceFixedWithFixed(store, write);
631    }
632
633    protected void lowerJavaReadNode(JavaReadNode read) {
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));
677                } else {
678                    newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph)));
679                }
680                recursiveLowerings.add(newObject);
681                graph.addBeforeFixed(commit, newObject);
682                allocations[objIndex] = newObject;
683                for (int i = 0; i < entryCount; i++) {
684                    ValueNode value = commit.getValues().get(valuePos);
685                    if (value instanceof VirtualObjectNode) {
686                        value = allocations[commit.getVirtualObjects().indexOf(value)];
687                    }
688                    if (value == null) {
689                        omittedValues.set(valuePos);
690                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
691                        // Constant.illegal is always the defaultForKind, so it is skipped
692                        JavaKind valueKind = value.getStackKind();
693                        JavaKind entryKind = virtual.entryKind(i);
694
695                        // Truffle requires some leniency in terms of what can be put where:
696                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
697                                        (valueKind == JavaKind.Long || valueKind == JavaKind.Double || (valueKind == JavaKind.Int && virtual instanceof VirtualArrayNode));
698                        AddressNode address = null;
699                        BarrierType barrierType = null;
700                        if (virtual instanceof VirtualInstanceNode) {
701                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
702                            long offset = fieldOffset(field);
703                            if (offset >= 0) {
704                                address = createOffsetAddress(graph, newObject, offset);
705                                barrierType = fieldInitializationBarrier(entryKind);
706                            }
707                        } else {
708                            address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
709                            barrierType = arrayInitializationBarrier(entryKind);
710                        }
711                        if (address != null) {
712                            WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
713                            graph.addAfterFixed(newObject, graph.add(write));
714                        }
715                    }
716                    valuePos++;
717
718                }
719            }
720            valuePos = 0;
721
722            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
723                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
724                int entryCount = virtual.entryCount();
725                ValueNode newObject = allocations[objIndex];
726                for (int i = 0; i < entryCount; i++) {
727                    if (omittedValues.get(valuePos)) {
728                        ValueNode value = commit.getValues().get(valuePos);
729                        assert value instanceof VirtualObjectNode;
730                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
731                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
732                            assert virtual.entryKind(i) == JavaKind.Object && allocValue.getStackKind() == JavaKind.Object;
733                            AddressNode address;
734                            BarrierType barrierType;
735                            if (virtual instanceof VirtualInstanceNode) {
736                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
737                                address = createFieldAddress(graph, newObject, virtualInstance.field(i));
738                                barrierType = BarrierType.IMPRECISE;
739                            } else {
740                                address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
741                                barrierType = BarrierType.PRECISE;
742                            }
743                            if (address != null) {
744                                WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
745                                graph.addBeforeFixed(commit, graph.add(write));
746                            }
747                        }
748                    }
749                    valuePos++;
750                }
751            }
752
753            finishAllocatedObjects(tool, commit, allocations);
754            graph.removeFixed(commit);
755
756            for (AbstractNewObjectNode recursiveLowering : recursiveLowerings) {
757                recursiveLowering.lower(tool);
758            }
759        }
760    }
761
762    public NewInstanceNode createNewInstanceFromVirtual(VirtualObjectNode virtual) {
763        return new NewInstanceNode(virtual.type(), true);
764    }
765
766    protected NewArrayNode createNewArrayFromVirtual(VirtualObjectNode virtual, ValueNode length) {
767        return new NewArrayNode(((VirtualArrayNode) virtual).componentType(), length, true);
768    }
769
770    public void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
771        StructuredGraph graph = commit.graph();
772        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
773            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
774            allocations[objIndex] = anchor;
775            graph.addBeforeFixed(commit, anchor);
776        }
777        /*
778         * Note that the FrameState that is assigned to these MonitorEnterNodes isn't the correct
779         * state. It will be the state from before the allocation occurred instead of a valid state
780         * after the locking is performed. In practice this should be fine since these are newly
781         * allocated objects. The bytecodes themselves permit allocating an object, doing a
782         * monitorenter and then dropping all references to the object which would produce the same
783         * state, though that would normally produce an IllegalMonitorStateException. In HotSpot
784         * some form of fast path locking should always occur so the FrameState should never
785         * actually be used.
786         */
787        ArrayList<MonitorEnterNode> enters = null;
788        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
789            List<MonitorIdNode> locks = commit.getLocks(objIndex);
790            if (locks.size() > 1) {
791                // Ensure that the lock operations are performed in lock depth order
792                ArrayList<MonitorIdNode> newList = new ArrayList<>(locks);
793                newList.sort((a, b) -> Integer.compare(a.getLockDepth(), b.getLockDepth()));
794                locks = newList;
795            }
796            int lastDepth = -1;
797            for (MonitorIdNode monitorId : locks) {
798                assert lastDepth < monitorId.getLockDepth();
799                lastDepth = monitorId.getLockDepth();
800                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
801                graph.addBeforeFixed(commit, enter);
802                if (enters == null) {
803                    enters = new ArrayList<>();
804                }
805                enters.add(enter);
806            }
807        }
808        for (Node usage : commit.usages().snapshot()) {
809            if (usage instanceof AllocatedObjectNode) {
810                AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
811                int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
812                addObject.replaceAtUsagesAndDelete(allocations[index]);
813            } else {
814                assert enters != null;
815                commit.replaceAtUsages(InputType.Memory, enters.get(enters.size() - 1));
816            }
817        }
818        if (enters != null) {
819            for (MonitorEnterNode enter : enters) {
820                enter.lower(tool);
821            }
822        }
823        assert commit.hasNoUsages();
824        insertAllocationBarrier(commit, graph);
825    }
826
827    /**
828     * Insert the required {@link MemoryBarriers#STORE_STORE} barrier for an allocation and also
829     * include the {@link MemoryBarriers#LOAD_STORE} required for final fields if any final fields
830     * are being written, as if {@link FinalFieldBarrierNode} were emitted.
831     */
832    private static void insertAllocationBarrier(CommitAllocationNode commit, StructuredGraph graph) {
833        int barrier = MemoryBarriers.STORE_STORE;
834        outer: for (VirtualObjectNode vobj : commit.getVirtualObjects()) {
835            for (ResolvedJavaField field : vobj.type().getInstanceFields(true)) {
836                if (field.isFinal()) {
837                    barrier = barrier | MemoryBarriers.LOAD_STORE;
838                    break outer;
839                }
840            }
841        }
842        graph.addAfterFixed(commit, graph.add(new MembarNode(barrier, LocationIdentity.init())));
843    }
844
845    /**
846     * @param field the field whose barrier type should be returned
847     */
848    protected BarrierType fieldLoadBarrierType(ResolvedJavaField field) {
849        return BarrierType.NONE;
850    }
851
852    protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
853        if (field.getJavaKind() == JavaKind.Object) {
854            return BarrierType.IMPRECISE;
855        }
856        return BarrierType.NONE;
857    }
858
859    protected BarrierType arrayStoreBarrierType(JavaKind elementKind) {
860        if (elementKind == JavaKind.Object) {
861            return BarrierType.PRECISE;
862        }
863        return BarrierType.NONE;
864    }
865
866    public BarrierType fieldInitializationBarrier(JavaKind entryKind) {
867        return entryKind == JavaKind.Object ? BarrierType.IMPRECISE : BarrierType.NONE;
868    }
869
870    public BarrierType arrayInitializationBarrier(JavaKind entryKind) {
871        return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE;
872    }
873
874    protected BarrierType unsafeStoreBarrierType(RawStoreNode store) {
875        if (!store.needsBarrier()) {
876            return BarrierType.NONE;
877        }
878        return storeBarrierType(store.object(), store.value());
879    }
880
881    protected BarrierType compareAndSwapBarrierType(UnsafeCompareAndSwapNode cas) {
882        return storeBarrierType(cas.object(), cas.expected());
883    }
884
885    protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
886        return storeBarrierType(n.object(), n.newValue());
887    }
888
889    protected BarrierType storeBarrierType(ValueNode object, ValueNode value) {
890        if (value.getStackKind() == JavaKind.Object) {
891            ResolvedJavaType type = StampTool.typeOrNull(object);
892            if (type != null && !type.isArray()) {
893                return BarrierType.IMPRECISE;
894            } else {
895                return BarrierType.PRECISE;
896            }
897        }
898        return BarrierType.NONE;
899    }
900
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}
1048