001/*
002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.replacements;
024
025import static com.oracle.graal.nodes.NamedLocationIdentity.*;
026import static com.oracle.graal.nodes.java.ArrayLengthNode.*;
027import static jdk.internal.jvmci.code.MemoryBarriers.*;
028import static jdk.internal.jvmci.meta.DeoptimizationAction.*;
029import static jdk.internal.jvmci.meta.DeoptimizationReason.*;
030
031import java.util.*;
032
033import jdk.internal.jvmci.code.*;
034import jdk.internal.jvmci.common.*;
035import jdk.internal.jvmci.meta.*;
036
037import com.oracle.graal.api.replacements.*;
038import com.oracle.graal.compiler.common.type.*;
039import com.oracle.graal.graph.*;
040import com.oracle.graal.nodes.*;
041import com.oracle.graal.nodes.calc.*;
042import com.oracle.graal.nodes.debug.*;
043import com.oracle.graal.nodes.extended.*;
044import com.oracle.graal.nodes.java.*;
045import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
046import com.oracle.graal.nodes.memory.*;
047import com.oracle.graal.nodes.memory.address.*;
048import com.oracle.graal.nodes.spi.*;
049import com.oracle.graal.nodes.type.*;
050import com.oracle.graal.nodes.util.*;
051import com.oracle.graal.nodes.virtual.*;
052import com.oracle.graal.phases.util.*;
053
054/**
055 * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
056 * implemented by VM-specific subclasses.
057 */
058public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
059
060    protected final MetaAccessProvider metaAccess;
061    protected final TargetDescription target;
062
063    private BoxingSnippets.Templates boxingSnippets;
064
065    public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, TargetDescription target) {
066        this.metaAccess = metaAccess;
067        this.target = target;
068    }
069
070    public void initialize(Providers providers, SnippetReflectionProvider snippetReflection) {
071        boxingSnippets = new BoxingSnippets.Templates(providers, snippetReflection, target);
072        providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(providers, snippetReflection, target));
073    }
074
075    @Override
076    public void lower(Node n, LoweringTool tool) {
077        assert n instanceof Lowerable;
078        StructuredGraph graph = (StructuredGraph) n.graph();
079        if (n instanceof LoadFieldNode) {
080            lowerLoadFieldNode((LoadFieldNode) n, tool);
081        } else if (n instanceof StoreFieldNode) {
082            lowerStoreFieldNode((StoreFieldNode) n, tool);
083        } else if (n instanceof LoadIndexedNode) {
084            lowerLoadIndexedNode((LoadIndexedNode) n, tool);
085        } else if (n instanceof StoreIndexedNode) {
086            lowerStoreIndexedNode((StoreIndexedNode) n, tool);
087        } else if (n instanceof ArrayLengthNode) {
088            lowerArrayLengthNode((ArrayLengthNode) n, tool);
089        } else if (n instanceof LoadHubNode) {
090            lowerLoadHubNode((LoadHubNode) n, tool);
091        } else if (n instanceof MonitorEnterNode) {
092            lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
093        } else if (n instanceof CompareAndSwapNode) {
094            lowerCompareAndSwapNode((CompareAndSwapNode) n);
095        } else if (n instanceof AtomicReadAndWriteNode) {
096            lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
097        } else if (n instanceof UnsafeLoadNode) {
098            lowerUnsafeLoadNode((UnsafeLoadNode) n, tool);
099        } else if (n instanceof UnsafeStoreNode) {
100            lowerUnsafeStoreNode((UnsafeStoreNode) n);
101        } else if (n instanceof JavaReadNode) {
102            lowerJavaReadNode((JavaReadNode) n);
103        } else if (n instanceof JavaWriteNode) {
104            lowerJavaWriteNode((JavaWriteNode) n);
105        } else if (n instanceof CommitAllocationNode) {
106            lowerCommitAllocationNode((CommitAllocationNode) n, tool);
107        } else if (n instanceof BoxNode) {
108            boxingSnippets.lower((BoxNode) n, tool);
109        } else if (n instanceof UnboxNode) {
110            boxingSnippets.lower((UnboxNode) n, tool);
111        } else if (n instanceof TypeCheckNode) {
112            lowerTypeCheckNode((TypeCheckNode) n, tool, graph);
113        } else if (n instanceof VerifyHeapNode) {
114            lowerVerifyHeap((VerifyHeapNode) n);
115        } else {
116            throw JVMCIError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
117        }
118    }
119
120    private void lowerTypeCheckNode(TypeCheckNode n, LoweringTool tool, StructuredGraph graph) {
121        ValueNode hub = createReadHub(graph, n.getValue(), null, tool);
122        ValueNode clazz = graph.unique(ConstantNode.forConstant(tool.getStampProvider().createHubStamp((ObjectStamp) n.getValue().stamp()), n.type().getObjectHub(), tool.getMetaAccess()));
123        LogicNode objectEquals = graph.unique(PointerEqualsNode.create(hub, clazz));
124        n.replaceAndDelete(objectEquals);
125    }
126
127    protected void lowerVerifyHeap(VerifyHeapNode n) {
128        GraphUtil.removeFixedWithUnusedInputs(n);
129    }
130
131    protected AddressNode createOffsetAddress(StructuredGraph graph, ValueNode object, long offset) {
132        ValueNode o = ConstantNode.forIntegerKind(target.wordKind, offset, graph);
133        return graph.unique(new OffsetAddressNode(object, o));
134    }
135
136    protected AddressNode createFieldAddress(StructuredGraph graph, ValueNode object, ResolvedJavaField field) {
137        int offset = fieldOffset(field);
138        if (offset >= 0) {
139            return createOffsetAddress(graph, object, offset);
140        } else {
141            return null;
142        }
143    }
144
145    protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
146        assert loadField.getKind() != Kind.Illegal;
147        StructuredGraph graph = loadField.graph();
148        ResolvedJavaField field = loadField.field();
149        ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
150        Stamp loadStamp = loadStamp(loadField.stamp(), field.getKind());
151
152        AddressNode address = createFieldAddress(graph, object, field);
153        assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
154
155        ReadNode memoryRead = graph.add(new ReadNode(address, field.getLocationIdentity(), loadStamp, fieldLoadBarrierType(field)));
156        ValueNode readValue = implicitLoadConvert(graph, field.getKind(), memoryRead);
157        loadField.replaceAtUsages(readValue);
158        graph.replaceFixed(loadField, memoryRead);
159
160        memoryRead.setGuard(createNullCheck(object, memoryRead, tool));
161
162        if (loadField.isVolatile()) {
163            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
164            graph.addBeforeFixed(memoryRead, preMembar);
165            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
166            graph.addAfterFixed(memoryRead, postMembar);
167        }
168    }
169
170    protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
171        StructuredGraph graph = storeField.graph();
172        ResolvedJavaField field = storeField.field();
173        ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
174        ValueNode value = implicitStoreConvert(graph, storeField.field().getKind(), storeField.value());
175        AddressNode address = createFieldAddress(graph, object, field);
176        assert address != null;
177
178        WriteNode memoryWrite = graph.add(new WriteNode(address, field.getLocationIdentity(), value, fieldStoreBarrierType(storeField.field())));
179        memoryWrite.setStateAfter(storeField.stateAfter());
180        graph.replaceFixedWithFixed(storeField, memoryWrite);
181        memoryWrite.setGuard(createNullCheck(object, memoryWrite, tool));
182
183        if (storeField.isVolatile()) {
184            MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
185            graph.addBeforeFixed(memoryWrite, preMembar);
186            MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
187            graph.addAfterFixed(memoryWrite, postMembar);
188        }
189    }
190
191    public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, Kind elementKind, ValueNode index) {
192        ValueNode wordIndex;
193        if (target.wordSize > 4) {
194            wordIndex = graph.unique(new SignExtendNode(index, target.wordSize * 8));
195        } else {
196            assert target.wordSize == 4 : "unsupported word size";
197            wordIndex = index;
198        }
199
200        int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
201        ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph)));
202
203        int base = arrayBaseOffset(elementKind);
204        ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordKind, base, graph)));
205
206        return graph.unique(new OffsetAddressNode(array, offset));
207    }
208
209    protected void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
210        StructuredGraph graph = loadIndexed.graph();
211        Kind elementKind = loadIndexed.elementKind();
212        Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
213
214        PiNode pi = getBoundsCheckedIndex(loadIndexed, tool, null);
215        ValueNode checkedIndex = pi;
216        if (checkedIndex == null) {
217            checkedIndex = loadIndexed.index();
218        }
219
220        AddressNode address = createArrayAddress(graph, loadIndexed.array(), elementKind, checkedIndex);
221        ReadNode memoryRead = graph.add(new ReadNode(address, NamedLocationIdentity.getArrayLocation(elementKind), loadStamp, BarrierType.NONE));
222        ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
223
224        if (pi != null) {
225            memoryRead.setGuard(pi.getGuard());
226        }
227
228        loadIndexed.replaceAtUsages(readValue);
229        graph.replaceFixed(loadIndexed, memoryRead);
230    }
231
232    protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
233        StructuredGraph graph = storeIndexed.graph();
234
235        GuardingNode[] nullCheckReturn = new GuardingNode[1];
236        PiNode pi = getBoundsCheckedIndex(storeIndexed, tool, nullCheckReturn);
237        ValueNode checkedIndex;
238        GuardingNode boundsCheck;
239        if (pi == null) {
240            checkedIndex = storeIndexed.index();
241            boundsCheck = null;
242        } else {
243            checkedIndex = pi;
244            boundsCheck = pi.getGuard();
245        }
246
247        Kind elementKind = storeIndexed.elementKind();
248
249        ValueNode value = storeIndexed.value();
250        ValueNode array = storeIndexed.array();
251        FixedWithNextNode checkCastNode = null;
252        if (elementKind == Kind.Object && !StampTool.isPointerAlwaysNull(value)) {
253            /* Array store check. */
254            ResolvedJavaType arrayType = StampTool.typeOrNull(array);
255            if (arrayType != null && StampTool.isExactType(array)) {
256                ResolvedJavaType elementType = arrayType.getComponentType();
257                if (!elementType.isJavaLangObject()) {
258                    ValueNode storeCheck = CheckCastNode.create(elementType, value, null, true, graph.getAssumptions());
259                    if (storeCheck.graph() == null) {
260                        checkCastNode = (CheckCastNode) storeCheck;
261                        checkCastNode = graph.add(checkCastNode);
262                        graph.addBeforeFixed(storeIndexed, checkCastNode);
263                    }
264                    value = storeCheck;
265                }
266            } else {
267                /*
268                 * The guard on the read hub should be the null check of the array that was
269                 * introduced earlier.
270                 */
271                GuardingNode nullCheck = nullCheckReturn[0];
272                assert nullCheckReturn[0] != null || createNullCheck(array, storeIndexed, tool) == null;
273                ValueNode arrayClass = createReadHub(graph, array, nullCheck, tool);
274                ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed, tool);
275                checkCastNode = graph.add(new CheckCastDynamicNode(componentHub, value, true));
276                graph.addBeforeFixed(storeIndexed, checkCastNode);
277                value = checkCastNode;
278            }
279        }
280
281        AddressNode address = createArrayAddress(graph, array, elementKind, checkedIndex);
282        WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
283                        arrayStoreBarrierType(storeIndexed.elementKind())));
284        memoryWrite.setGuard(boundsCheck);
285        memoryWrite.setStateAfter(storeIndexed.stateAfter());
286        graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
287
288        if (checkCastNode instanceof Lowerable) {
289            /* Recursive lowering of the store check node. */
290            ((Lowerable) checkCastNode).lower(tool);
291        }
292    }
293
294    protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
295        StructuredGraph graph = arrayLengthNode.graph();
296        ValueNode array = arrayLengthNode.array();
297
298        AddressNode address = createOffsetAddress(graph, array, arrayLengthOffset());
299        ReadNode arrayLengthRead = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, StampFactory.positiveInt(), BarrierType.NONE));
300        arrayLengthRead.setGuard(createNullCheck(array, arrayLengthNode, tool));
301        graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
302    }
303
304    protected void lowerLoadHubNode(LoadHubNode loadHub, LoweringTool tool) {
305        StructuredGraph graph = loadHub.graph();
306        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
307            return;
308        }
309        if (graph.getGuardsStage().allowsFloatingGuards()) {
310            return;
311        }
312        ValueNode hub = createReadHub(graph, loadHub.getValue(), loadHub.getGuard(), tool);
313        graph.replaceFloating(loadHub, hub);
314    }
315
316    protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
317        ValueNode object = monitorEnter.object();
318        GuardingNode nullCheck = createNullCheck(object, monitorEnter, tool);
319        if (nullCheck != null) {
320            object = graph.unique(new PiNode(object, ((ObjectStamp) object.stamp()).improveWith(StampFactory.objectNonNull()), (ValueNode) nullCheck));
321        }
322        ValueNode hub = graph.addOrUnique(LoadHubNode.create(object, tool.getStampProvider(), tool.getMetaAccess()));
323        RawMonitorEnterNode rawMonitorEnter = graph.add(new RawMonitorEnterNode(object, hub, monitorEnter.getMonitorId()));
324        rawMonitorEnter.setStateBefore(monitorEnter.stateBefore());
325        rawMonitorEnter.setStateAfter(monitorEnter.stateAfter());
326        graph.replaceFixedWithFixed(monitorEnter, rawMonitorEnter);
327    }
328
329    protected void lowerCompareAndSwapNode(CompareAndSwapNode cas) {
330        StructuredGraph graph = cas.graph();
331        Kind valueKind = cas.getValueKind();
332
333        ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
334        ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
335
336        AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
337        LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, compareAndSwapBarrierType(cas)));
338        atomicNode.setStateAfter(cas.stateAfter());
339        graph.replaceFixedWithFixed(cas, atomicNode);
340    }
341
342    protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
343        StructuredGraph graph = n.graph();
344        Kind valueKind = n.getValueKind();
345
346        ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
347
348        AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
349        LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, atomicReadAndWriteBarrierType(n)));
350        memoryRead.setStateAfter(n.stateAfter());
351
352        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
353        n.stateAfter().replaceFirstInput(n, memoryRead);
354        n.replaceAtUsages(readValue);
355        graph.replaceFixedWithFixed(n, memoryRead);
356    }
357
358    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, @SuppressWarnings("unused") LoweringTool tool) {
359        StructuredGraph graph = load.graph();
360        if (load.getGuardingCondition() != null) {
361            ConditionAnchorNode valueAnchorNode = graph.add(new ConditionAnchorNode(load.getGuardingCondition()));
362            ReadNode memoryRead = createUnsafeRead(graph, load, valueAnchorNode);
363            graph.replaceFixedWithFixed(load, valueAnchorNode);
364            graph.addAfterFixed(valueAnchorNode, memoryRead);
365        } else {
366            assert load.getKind() != Kind.Illegal;
367            ReadNode memoryRead = createUnsafeRead(graph, load, null);
368            graph.replaceFixedWithFixed(load, memoryRead);
369        }
370    }
371
372    protected AddressNode createUnsafeAddress(StructuredGraph graph, ValueNode object, ValueNode offset) {
373        if (object.isConstant() && object.asConstant().isDefaultForKind()) {
374            return graph.unique(new RawAddressNode(offset));
375        } else {
376            return graph.unique(new OffsetAddressNode(object, offset));
377        }
378    }
379
380    protected ReadNode createUnsafeRead(StructuredGraph graph, UnsafeLoadNode load, GuardingNode guard) {
381        boolean compressible = load.accessKind() == Kind.Object;
382        Kind readKind = load.accessKind();
383        Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
384        AddressNode address = createUnsafeAddress(graph, load.object(), load.offset());
385        ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, guard, BarrierType.NONE));
386        if (guard == null) {
387            // An unsafe read must not float otherwise it may float above
388            // a test guaranteeing the read is safe.
389            memoryRead.setForceFixed(true);
390        }
391        ValueNode readValue = implicitLoadConvert(graph, readKind, memoryRead, compressible);
392        load.replaceAtUsages(readValue);
393        return memoryRead;
394    }
395
396    protected void lowerUnsafeStoreNode(UnsafeStoreNode store) {
397        StructuredGraph graph = store.graph();
398        boolean compressible = store.value().getKind() == Kind.Object;
399        Kind valueKind = store.accessKind();
400        ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
401        AddressNode address = createUnsafeAddress(graph, store.object(), store.offset());
402        WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, unsafeStoreBarrierType(store)));
403        write.setStateAfter(store.stateAfter());
404        graph.replaceFixedWithFixed(store, write);
405    }
406
407    protected void lowerJavaReadNode(JavaReadNode read) {
408        StructuredGraph graph = read.graph();
409        Kind valueKind = read.getReadKind();
410        Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
411
412        ReadNode memoryRead = graph.add(new ReadNode(read.getAddress(), read.getLocationIdentity(), loadStamp, read.getBarrierType()));
413        GuardingNode guard = read.getGuard();
414        ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
415        if (guard == null) {
416            // An unsafe read must not float otherwise it may float above
417            // a test guaranteeing the read is safe.
418            memoryRead.setForceFixed(true);
419        } else {
420            memoryRead.setGuard(guard);
421        }
422        read.replaceAtUsages(readValue);
423        graph.replaceFixed(read, memoryRead);
424    }
425
426    protected void lowerJavaWriteNode(JavaWriteNode write) {
427        StructuredGraph graph = write.graph();
428        Kind valueKind = write.getWriteKind();
429        ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
430
431        WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType(), write.isInitialization()));
432        memoryWrite.setStateAfter(write.stateAfter());
433        graph.replaceFixedWithFixed(write, memoryWrite);
434        memoryWrite.setGuard(write.getGuard());
435    }
436
437    protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
438        StructuredGraph graph = commit.graph();
439        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
440            List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
441
442            ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
443            BitSet omittedValues = new BitSet();
444            int valuePos = 0;
445            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
446                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
447                int entryCount = virtual.entryCount();
448                AbstractNewObjectNode newObject;
449                if (virtual instanceof VirtualInstanceNode) {
450                    newObject = graph.add(createNewInstanceFromVirtual(virtual));
451                } else {
452                    newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph)));
453                }
454                recursiveLowerings.add(newObject);
455                graph.addBeforeFixed(commit, newObject);
456                allocations[objIndex] = newObject;
457                for (int i = 0; i < entryCount; i++) {
458                    ValueNode value = commit.getValues().get(valuePos);
459                    if (value instanceof VirtualObjectNode) {
460                        value = allocations[commit.getVirtualObjects().indexOf(value)];
461                    }
462                    if (value == null) {
463                        omittedValues.set(valuePos);
464                    } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
465                        // Constant.illegal is always the defaultForKind, so it is skipped
466                        Kind valueKind = value.getKind();
467                        Kind entryKind = virtual.entryKind(i);
468
469                        // Truffle requires some leniency in terms of what can be put where:
470                        assert valueKind.getStackKind() == entryKind.getStackKind() ||
471                                        (valueKind == Kind.Long || valueKind == Kind.Double || (valueKind == Kind.Int && virtual instanceof VirtualArrayNode));
472                        AddressNode address = null;
473                        BarrierType barrierType = null;
474                        if (virtual instanceof VirtualInstanceNode) {
475                            ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
476                            long offset = fieldOffset(field);
477                            if (offset >= 0) {
478                                address = createOffsetAddress(graph, newObject, offset);
479                                barrierType = fieldInitializationBarrier(entryKind);
480                            }
481                        } else {
482                            address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
483                            barrierType = arrayInitializationBarrier(entryKind);
484                        }
485                        if (address != null) {
486                            WriteNode write = new WriteNode(address, initLocationIdentity(), implicitStoreConvert(graph, entryKind, value), barrierType);
487                            graph.addAfterFixed(newObject, graph.add(write));
488                        }
489                    }
490                    valuePos++;
491
492                }
493            }
494            valuePos = 0;
495
496            for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
497                VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
498                int entryCount = virtual.entryCount();
499                ValueNode newObject = allocations[objIndex];
500                for (int i = 0; i < entryCount; i++) {
501                    if (omittedValues.get(valuePos)) {
502                        ValueNode value = commit.getValues().get(valuePos);
503                        assert value instanceof VirtualObjectNode;
504                        ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
505                        if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
506                            assert virtual.entryKind(i) == Kind.Object && allocValue.getKind() == Kind.Object;
507                            AddressNode address;
508                            BarrierType barrierType;
509                            if (virtual instanceof VirtualInstanceNode) {
510                                VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
511                                address = createFieldAddress(graph, newObject, virtualInstance.field(i));
512                                barrierType = BarrierType.IMPRECISE;
513                            } else {
514                                address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
515                                barrierType = BarrierType.PRECISE;
516                            }
517                            if (address != null) {
518                                WriteNode write = new WriteNode(address, initLocationIdentity(), implicitStoreConvert(graph, Kind.Object, allocValue), barrierType);
519                                graph.addBeforeFixed(commit, graph.add(write));
520                            }
521                        }
522                    }
523                    valuePos++;
524                }
525            }
526
527            finishAllocatedObjects(tool, commit, allocations);
528            graph.removeFixed(commit);
529
530            for (AbstractNewObjectNode recursiveLowering : recursiveLowerings) {
531                recursiveLowering.lower(tool);
532            }
533        }
534    }
535
536    public NewInstanceNode createNewInstanceFromVirtual(VirtualObjectNode virtual) {
537        return new NewInstanceNode(virtual.type(), true);
538    }
539
540    protected NewArrayNode createNewArrayFromVirtual(VirtualObjectNode virtual, ValueNode length) {
541        return new NewArrayNode(((VirtualArrayNode) virtual).componentType(), length, true);
542    }
543
544    public static void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
545        StructuredGraph graph = commit.graph();
546        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
547            FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
548            allocations[objIndex] = anchor;
549            graph.addBeforeFixed(commit, anchor);
550        }
551        for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
552            for (MonitorIdNode monitorId : commit.getLocks(objIndex)) {
553                MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
554                graph.addBeforeFixed(commit, enter);
555                enter.lower(tool);
556            }
557        }
558        for (Node usage : commit.usages().snapshot()) {
559            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
560            int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
561            graph.replaceFloating(addObject, allocations[index]);
562        }
563    }
564
565    protected BarrierType fieldLoadBarrierType(@SuppressWarnings("unused") ResolvedJavaField field) {
566        return BarrierType.NONE;
567    }
568
569    protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
570        if (field.getKind() == Kind.Object) {
571            return BarrierType.IMPRECISE;
572        }
573        return BarrierType.NONE;
574    }
575
576    protected BarrierType arrayStoreBarrierType(Kind elementKind) {
577        if (elementKind == Kind.Object) {
578            return BarrierType.PRECISE;
579        }
580        return BarrierType.NONE;
581    }
582
583    protected BarrierType fieldInitializationBarrier(Kind entryKind) {
584        return entryKind == Kind.Object ? BarrierType.IMPRECISE : BarrierType.NONE;
585    }
586
587    protected BarrierType arrayInitializationBarrier(Kind entryKind) {
588        return entryKind == Kind.Object ? BarrierType.PRECISE : BarrierType.NONE;
589    }
590
591    protected BarrierType unsafeStoreBarrierType(UnsafeStoreNode store) {
592        return storeBarrierType(store.object(), store.value());
593    }
594
595    protected BarrierType compareAndSwapBarrierType(CompareAndSwapNode cas) {
596        return storeBarrierType(cas.object(), cas.expected());
597    }
598
599    protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
600        return storeBarrierType(n.object(), n.newValue());
601    }
602
603    protected BarrierType storeBarrierType(ValueNode object, ValueNode value) {
604        if (value.getKind() == Kind.Object) {
605            ResolvedJavaType type = StampTool.typeOrNull(object);
606            if (type != null && !type.isArray()) {
607                return BarrierType.IMPRECISE;
608            } else {
609                return BarrierType.PRECISE;
610            }
611        }
612        return BarrierType.NONE;
613    }
614
615    protected abstract int fieldOffset(ResolvedJavaField field);
616
617    protected abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
618
619    protected abstract int arrayLengthOffset();
620
621    protected abstract int arrayBaseOffset(Kind elementKind);
622
623    public int arrayScalingFactor(Kind elementKind) {
624        return target.getSizeInBytes(elementKind);
625    }
626
627    protected abstract LocationIdentity initLocationIdentity();
628
629    public Stamp loadStamp(Stamp stamp, Kind kind) {
630        return loadStamp(stamp, kind, true);
631    }
632
633    protected Stamp loadStamp(Stamp stamp, Kind kind, @SuppressWarnings("unused") boolean compressible) {
634        switch (kind) {
635            case Boolean:
636            case Byte:
637                return IntegerStamp.OPS.getNarrow().foldStamp(32, 8, stamp);
638            case Char:
639            case Short:
640                return IntegerStamp.OPS.getNarrow().foldStamp(32, 16, stamp);
641        }
642        return stamp;
643    }
644
645    public ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value) {
646        return implicitLoadConvert(graph, kind, value, true);
647
648    }
649
650    protected ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
651        switch (kind) {
652            case Byte:
653            case Short:
654                return graph.unique(new SignExtendNode(value, 32));
655            case Boolean:
656            case Char:
657                return graph.unique(new ZeroExtendNode(value, 32));
658        }
659        return value;
660    }
661
662    public ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value) {
663        return implicitStoreConvert(graph, kind, value, true);
664    }
665
666    protected ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, @SuppressWarnings("unused") boolean compressible) {
667        switch (kind) {
668            case Boolean:
669            case Byte:
670                return graph.unique(new NarrowNode(value, 8));
671            case Char:
672            case Short:
673                return graph.unique(new NarrowNode(value, 16));
674        }
675        return value;
676    }
677
678    protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool);
679
680    protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor, LoweringTool tool);
681
682    protected PiNode getBoundsCheckedIndex(AccessIndexedNode n, LoweringTool tool, GuardingNode[] nullCheckReturn) {
683        StructuredGraph graph = n.graph();
684        ValueNode array = n.array();
685        ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
686        if (arrayLength == null) {
687            Stamp stamp = StampFactory.positiveInt();
688            AddressNode address = createOffsetAddress(graph, array, arrayLengthOffset());
689            ReadNode readArrayLength = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, stamp, BarrierType.NONE));
690            graph.addBeforeFixed(n, readArrayLength);
691            GuardingNode nullCheck = createNullCheck(array, readArrayLength, tool);
692            if (nullCheckReturn != null) {
693                nullCheckReturn[0] = nullCheck;
694            }
695            readArrayLength.setGuard(nullCheck);
696            arrayLength = readArrayLength;
697        } else {
698            arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
699        }
700
701        if (arrayLength.isConstant() && n.index().isConstant()) {
702            int l = arrayLength.asJavaConstant().asInt();
703            int i = n.index().asJavaConstant().asInt();
704            if (i >= 0 && i < l) {
705                // unneeded range check
706                return null;
707            }
708        }
709
710        GuardingNode guard = tool.createGuard(n, graph.unique(new IntegerBelowNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
711        IntegerStamp lengthStamp = (IntegerStamp) arrayLength.stamp();
712        IntegerStamp indexStamp = StampFactory.forInteger(32, 0, lengthStamp.upperBound());
713        return graph.unique(new PiNode(n.index(), indexStamp, guard.asNode()));
714    }
715
716    protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
717        if (StampTool.isPointerNonNull(object)) {
718            return null;
719        }
720        return tool.createGuard(before, before.graph().unique(new IsNullNode(object)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, JavaConstant.NULL_POINTER,
721                        true);
722    }
723
724    @Override
725    public ValueNode reconstructArrayIndex(Kind elementKind, AddressNode address) {
726        StructuredGraph graph = address.graph();
727        ValueNode offset = ((OffsetAddressNode) address).getOffset();
728
729        int base = arrayBaseOffset(elementKind);
730        ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), base, graph)));
731
732        int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
733        ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph)));
734        return IntegerConvertNode.convert(ret, StampFactory.forKind(Kind.Int), graph);
735    }
736}