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.hotspot.meta;
024
025import static com.oracle.graal.compiler.common.GraalOptions.*;
026import static com.oracle.graal.hotspot.meta.HotSpotForeignCallsProviderImpl.*;
027import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
028import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
029import static jdk.internal.jvmci.meta.LocationIdentity.*;
030
031import java.lang.ref.*;
032
033import jdk.internal.jvmci.code.*;
034import jdk.internal.jvmci.common.*;
035import jdk.internal.jvmci.hotspot.*;
036import jdk.internal.jvmci.meta.*;
037
038import com.oracle.graal.compiler.common.spi.*;
039import com.oracle.graal.compiler.common.type.*;
040import com.oracle.graal.graph.*;
041import com.oracle.graal.hotspot.*;
042import com.oracle.graal.hotspot.nodes.*;
043import com.oracle.graal.hotspot.nodes.type.*;
044import com.oracle.graal.hotspot.replacements.*;
045import com.oracle.graal.hotspot.replacements.arraycopy.*;
046import com.oracle.graal.nodes.*;
047import com.oracle.graal.nodes.calc.*;
048import com.oracle.graal.nodes.debug.*;
049import com.oracle.graal.nodes.extended.*;
050import com.oracle.graal.nodes.java.*;
051import com.oracle.graal.nodes.memory.*;
052import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
053import com.oracle.graal.nodes.memory.address.*;
054import com.oracle.graal.nodes.spi.*;
055import com.oracle.graal.nodes.type.*;
056import com.oracle.graal.replacements.*;
057import com.oracle.graal.replacements.nodes.*;
058
059/**
060 * HotSpot implementation of {@link LoweringProvider}.
061 */
062public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider {
063
064    protected final HotSpotGraalRuntimeProvider runtime;
065    protected final ForeignCallsProvider foreignCalls;
066    protected final HotSpotRegistersProvider registers;
067
068    protected CheckCastDynamicSnippets.Templates checkcastDynamicSnippets;
069    protected InstanceOfSnippets.Templates instanceofSnippets;
070    protected NewObjectSnippets.Templates newObjectSnippets;
071    protected MonitorSnippets.Templates monitorSnippets;
072    protected WriteBarrierSnippets.Templates writeBarrierSnippets;
073    protected LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
074    protected UnsafeLoadSnippets.Templates unsafeLoadSnippets;
075    protected AssertionSnippets.Templates assertionSnippets;
076    protected ArrayCopySnippets.Templates arraycopySnippets;
077
078    public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
079                    TargetDescription target) {
080        super(metaAccess, target);
081        this.runtime = runtime;
082        this.foreignCalls = foreignCalls;
083        this.registers = registers;
084    }
085
086    public void initialize(HotSpotProviders providers, HotSpotVMConfig config) {
087        super.initialize(providers, providers.getSnippetReflection());
088
089        assert target == providers.getCodeCache().getTarget();
090        checkcastDynamicSnippets = new CheckCastDynamicSnippets.Templates(providers, target);
091        instanceofSnippets = new InstanceOfSnippets.Templates(providers, target);
092        newObjectSnippets = new NewObjectSnippets.Templates(providers, target);
093        monitorSnippets = new MonitorSnippets.Templates(providers, target, config.useFastLocking);
094        writeBarrierSnippets = new WriteBarrierSnippets.Templates(providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
095        exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(providers, target);
096        unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(providers, target);
097        assertionSnippets = new AssertionSnippets.Templates(providers, target);
098        arraycopySnippets = new ArrayCopySnippets.Templates(providers, target);
099        providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(providers, target));
100    }
101
102    @Override
103    public void lower(Node n, LoweringTool tool) {
104        StructuredGraph graph = (StructuredGraph) n.graph();
105        if (n instanceof Invoke) {
106            lowerInvoke((Invoke) n, tool, graph);
107        } else if (n instanceof LoadMethodNode) {
108            lowerLoadMethodNode((LoadMethodNode) n);
109        } else if (n instanceof GetClassNode) {
110            lowerGetClassNode((GetClassNode) n, tool, graph);
111        } else if (n instanceof StoreHubNode) {
112            lowerStoreHubNode((StoreHubNode) n, graph);
113        } else if (n instanceof OSRStartNode) {
114            lowerOSRStartNode((OSRStartNode) n);
115        } else if (n instanceof BytecodeExceptionNode) {
116            lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
117        } else if (n instanceof CheckCastDynamicNode) {
118            checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
119        } else if (n instanceof InstanceOfNode) {
120            if (graph.getGuardsStage().areDeoptsFixed()) {
121                instanceofSnippets.lower((InstanceOfNode) n, tool);
122            }
123        } else if (n instanceof InstanceOfDynamicNode) {
124            if (graph.getGuardsStage().areDeoptsFixed()) {
125                instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
126            }
127        } else if (n instanceof ClassIsAssignableFromNode) {
128            if (graph.getGuardsStage().areDeoptsFixed()) {
129                instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
130            }
131        } else if (n instanceof NewInstanceNode) {
132            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
133                newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
134            }
135        } else if (n instanceof DynamicNewInstanceNode) {
136            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
137                newObjectSnippets.lower((DynamicNewInstanceNode) n, registers, tool);
138            }
139        } else if (n instanceof NewArrayNode) {
140            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
141                newObjectSnippets.lower((NewArrayNode) n, registers, runtime, tool);
142            }
143        } else if (n instanceof DynamicNewArrayNode) {
144            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
145                newObjectSnippets.lower((DynamicNewArrayNode) n, registers, tool);
146            }
147        } else if (n instanceof VerifyHeapNode) {
148            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
149                newObjectSnippets.lower((VerifyHeapNode) n, registers, runtime, tool);
150            }
151        } else if (n instanceof RawMonitorEnterNode) {
152            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
153                monitorSnippets.lower((RawMonitorEnterNode) n, registers, tool);
154            }
155        } else if (n instanceof MonitorExitNode) {
156            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
157                monitorSnippets.lower((MonitorExitNode) n, tool);
158            }
159        } else if (n instanceof ArrayCopyNode) {
160            arraycopySnippets.lower((ArrayCopyNode) n, tool);
161        } else if (n instanceof ArrayCopySlowPathNode) {
162            arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool);
163        } else if (n instanceof ArrayCopyUnrollNode) {
164            arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool);
165        } else if (n instanceof G1PreWriteBarrier) {
166            writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
167        } else if (n instanceof G1PostWriteBarrier) {
168            writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
169        } else if (n instanceof G1ReferentFieldReadBarrier) {
170            writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
171        } else if (n instanceof SerialWriteBarrier) {
172            writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
173        } else if (n instanceof SerialArrayRangeWriteBarrier) {
174            writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
175        } else if (n instanceof G1ArrayRangePreWriteBarrier) {
176            writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
177        } else if (n instanceof G1ArrayRangePostWriteBarrier) {
178            writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
179        } else if (n instanceof NewMultiArrayNode) {
180            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
181                newObjectSnippets.lower((NewMultiArrayNode) n, tool);
182            }
183        } else if (n instanceof LoadExceptionObjectNode) {
184            exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
185        } else if (n instanceof AssertionNode) {
186            assertionSnippets.lower((AssertionNode) n, tool);
187        } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
188            // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
189            // zero and the MIN_VALUE / -1 cases.
190        } else if (n instanceof AbstractDeoptimizeNode || n instanceof UnwindNode || n instanceof RemNode) {
191            /* No lowering, we generate LIR directly for these nodes. */
192        } else if (n instanceof ClassGetHubNode) {
193            lowerClassGetHubNode((ClassGetHubNode) n, tool);
194        } else if (n instanceof HubGetClassNode) {
195            lowerHubGetClassNode((HubGetClassNode) n, tool);
196        } else if (n instanceof KlassLayoutHelperNode) {
197            lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool);
198        } else if (n instanceof ComputeObjectAddressNode) {
199            if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
200                lowerComputeObjectAddressNode((ComputeObjectAddressNode) n);
201            }
202        } else {
203            super.lower(n, tool);
204        }
205    }
206
207    private static void lowerComputeObjectAddressNode(ComputeObjectAddressNode n) {
208        /*
209         * Lower the node into a ComputeObjectAddress node and an Add but ensure that it's below any
210         * potential safepoints and above it's uses.
211         */
212        for (Node use : n.usages().snapshot()) {
213            if (use instanceof FixedNode) {
214                FixedNode fixed = (FixedNode) use;
215                StructuredGraph graph = n.graph();
216                GetObjectAddressNode address = graph.add(new GetObjectAddressNode(n.getObject()));
217                graph.addBeforeFixed(fixed, address);
218                AddNode add = graph.addOrUnique(new AddNode(address, n.getOffset()));
219                graph.replaceFixedWithFloating(n, add);
220            } else {
221                throw JVMCIError.shouldNotReachHere("Unexpected floating use of ComputeObjectAddressNode");
222            }
223        }
224    }
225
226    private void lowerKlassLayoutHelperNode(KlassLayoutHelperNode n, LoweringTool tool) {
227        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
228            return;
229        }
230        StructuredGraph graph = n.graph();
231        assert !n.getHub().isConstant();
232        AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getConfig().klassLayoutHelperOffset);
233        graph.replaceFloating(n, graph.unique(new FloatingReadNode(address, KLASS_LAYOUT_HELPER_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE)));
234    }
235
236    private void lowerHubGetClassNode(HubGetClassNode n, LoweringTool tool) {
237        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
238            return;
239        }
240
241        StructuredGraph graph = n.graph();
242        assert !n.getHub().isConstant();
243        AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getConfig().classMirrorOffset);
244        FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
245        graph.replaceFloating(n, read);
246    }
247
248    private void lowerClassGetHubNode(ClassGetHubNode n, LoweringTool tool) {
249        if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
250            return;
251        }
252
253        StructuredGraph graph = n.graph();
254        assert !n.getValue().isConstant();
255        AddressNode address = createOffsetAddress(graph, n.getValue(), runtime.getConfig().klassOffset);
256        FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_KLASS_LOCATION, null, n.stamp(), n.getGuard(), BarrierType.NONE));
257        graph.replaceFloating(n, read);
258    }
259
260    private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) {
261        if (invoke.callTarget() instanceof MethodCallTargetNode) {
262            MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
263            NodeInputList<ValueNode> parameters = callTarget.arguments();
264            ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
265            GuardingNode receiverNullCheck = null;
266            if (!callTarget.isStatic() && receiver.stamp() instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) {
267                receiverNullCheck = createNullCheck(receiver, invoke.asNode(), tool);
268                invoke.setGuard(receiverNullCheck);
269            }
270            JavaType[] signature = callTarget.targetMethod().getSignature().toParameterTypes(callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
271
272            LoweredCallTargetNode loweredCallTarget = null;
273            if (InlineVTableStubs.getValue() && callTarget.invokeKind().isIndirect() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
274                HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
275                ResolvedJavaType receiverType = invoke.getReceiverType();
276                if (hsMethod.isInVirtualMethodTable(receiverType)) {
277                    Kind wordKind = runtime.getTarget().wordKind;
278                    ValueNode hub = createReadHub(graph, receiver, receiverNullCheck, tool);
279
280                    ReadNode metaspaceMethod = createReadVirtualMethod(graph, hub, hsMethod, receiverType);
281                    // We use LocationNode.ANY_LOCATION for the reads that access the
282                    // compiled code entry as HotSpot does not guarantee they are final
283                    // values.
284                    int methodCompiledEntryOffset = runtime.getConfig().methodCompiledEntryOffset;
285                    AddressNode address = createOffsetAddress(graph, metaspaceMethod, methodCompiledEntryOffset);
286                    ReadNode compiledEntry = graph.add(new ReadNode(address, any(), StampFactory.forKind(wordKind), BarrierType.NONE));
287
288                    loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
289                                    CallingConvention.Type.JavaCall, callTarget.invokeKind()));
290
291                    graph.addBeforeFixed(invoke.asNode(), metaspaceMethod);
292                    graph.addAfterFixed(metaspaceMethod, compiledEntry);
293                }
294            }
295
296            if (loweredCallTarget == null) {
297                loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
298                                callTarget.invokeKind()));
299            }
300            callTarget.replaceAndDelete(loweredCallTarget);
301        }
302    }
303
304    @Override
305    protected Stamp loadStamp(Stamp stamp, Kind kind, boolean compressible) {
306        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
307            return NarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getConfig().getOopEncoding());
308        }
309        return super.loadStamp(stamp, kind, compressible);
310    }
311
312    @Override
313    protected ValueNode implicitLoadConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
314        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
315            return CompressionNode.uncompress(value, runtime.getConfig().getOopEncoding());
316        }
317        return super.implicitLoadConvert(graph, kind, value, compressible);
318    }
319
320    @Override
321    protected ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) {
322        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
323        JavaConstant base = field.getDeclaringClass().getJavaClass();
324        return ConstantNode.forConstant(base, metaAccess, graph);
325    }
326
327    @Override
328    protected ValueNode implicitStoreConvert(StructuredGraph graph, Kind kind, ValueNode value, boolean compressible) {
329        if (kind == Kind.Object && compressible && runtime.getConfig().useCompressedOops) {
330            return CompressionNode.compress(value, runtime.getConfig().getOopEncoding());
331        }
332        return super.implicitStoreConvert(graph, kind, value, compressible);
333    }
334
335    @Override
336    protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor, LoweringTool tool) {
337        /*
338         * Anchor the read of the element klass to the cfg, because it is only valid when arrayClass
339         * is an object class, which might not be the case in other parts of the compiled method.
340         */
341        AddressNode address = createOffsetAddress(graph, arrayHub, runtime.getConfig().arrayClassElementOffset);
342        return graph.unique(new FloatingReadNode(address, OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION, null, tool.getStampProvider().createHubStamp(true), AbstractBeginNode.prevBegin(anchor)));
343    }
344
345    @Override
346    protected void lowerUnsafeLoadNode(UnsafeLoadNode load, LoweringTool tool) {
347        StructuredGraph graph = load.graph();
348        if (load.getGuardingCondition() == null && !graph.getGuardsStage().allowsFloatingGuards() && addReadBarrier(load)) {
349            unsafeLoadSnippets.lower(load, tool);
350        } else {
351            super.lowerUnsafeLoadNode(load, tool);
352        }
353    }
354
355    private void lowerLoadMethodNode(LoadMethodNode loadMethodNode) {
356        StructuredGraph graph = loadMethodNode.graph();
357        HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) loadMethodNode.getMethod();
358        ReadNode metaspaceMethod = createReadVirtualMethod(graph, loadMethodNode.getHub(), method, loadMethodNode.getReceiverType());
359        graph.replaceFixed(loadMethodNode, metaspaceMethod);
360    }
361
362    private static void lowerGetClassNode(GetClassNode getClass, LoweringTool tool, StructuredGraph graph) {
363        StampProvider stampProvider = tool.getStampProvider();
364        LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, getClass.getObject()));
365        HubGetClassNode hubGetClass = graph.unique(new HubGetClassNode(tool.getMetaAccess(), hub));
366        graph.replaceFloating(getClass, hubGetClass);
367        hub.lower(tool);
368        hubGetClass.lower(tool);
369    }
370
371    private void lowerStoreHubNode(StoreHubNode storeHub, StructuredGraph graph) {
372        WriteNode hub = createWriteHub(graph, storeHub.getObject(), storeHub.getValue());
373        graph.replaceFixed(storeHub, hub);
374    }
375
376    @Override
377    protected BarrierType fieldInitializationBarrier(Kind entryKind) {
378        return (entryKind == Kind.Object && !runtime.getConfig().useDeferredInitBarriers) ? BarrierType.IMPRECISE : BarrierType.NONE;
379    }
380
381    @Override
382    protected BarrierType arrayInitializationBarrier(Kind entryKind) {
383        return (entryKind == Kind.Object && !runtime.getConfig().useDeferredInitBarriers) ? BarrierType.PRECISE : BarrierType.NONE;
384    }
385
386    private void lowerOSRStartNode(OSRStartNode osrStart) {
387        StructuredGraph graph = osrStart.graph();
388        if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
389            StartNode newStart = graph.add(new StartNode());
390            ParameterNode buffer = graph.unique(new ParameterNode(0, StampFactory.forKind(runtime.getTarget().wordKind)));
391            ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(foreignCalls, OSR_MIGRATION_END, buffer));
392            migrationEnd.setStateAfter(osrStart.stateAfter());
393
394            newStart.setNext(migrationEnd);
395            FixedNode next = osrStart.next();
396            osrStart.setNext(null);
397            migrationEnd.setNext(next);
398            graph.setStart(newStart);
399
400            // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
401            int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
402            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) {
403                int size = osrLocal.getKind().getSlotCount();
404                int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
405                AddressNode address = createOffsetAddress(graph, buffer, offset);
406                ReadNode load = graph.add(new ReadNode(address, any(), osrLocal.stamp(), BarrierType.NONE));
407                osrLocal.replaceAndDelete(load);
408                graph.addBeforeFixed(migrationEnd, load);
409            }
410            osrStart.replaceAtUsages(newStart);
411            osrStart.safeDelete();
412        }
413    }
414
415    static final class Exceptions {
416        protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
417        protected static final NullPointerException cachedNullPointerException;
418
419        static {
420            cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
421            cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
422            cachedNullPointerException = new NullPointerException();
423            cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
424        }
425    }
426
427    public static final class RuntimeCalls {
428        public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
429        public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
430    }
431
432    private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
433        StructuredGraph graph = node.graph();
434        if (graph.getGuardsStage().allowsFloatingGuards()) {
435            if (OmitHotExceptionStacktrace.getValue()) {
436                Throwable exception;
437                if (node.getExceptionClass() == NullPointerException.class) {
438                    exception = Exceptions.cachedNullPointerException;
439                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
440                    exception = Exceptions.cachedArrayIndexOutOfBoundsException;
441                } else {
442                    throw JVMCIError.shouldNotReachHere();
443                }
444                FloatingNode exceptionNode = ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(exception), metaAccess, graph);
445                graph.replaceFixedWithFloating(node, exceptionNode);
446
447            } else {
448                ForeignCallDescriptor descriptor;
449                if (node.getExceptionClass() == NullPointerException.class) {
450                    descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
451                } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
452                    descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
453                } else {
454                    throw JVMCIError.shouldNotReachHere();
455                }
456
457                ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(), node.getArguments()));
458                graph.replaceFixedWithFixed(node, foreignCallNode);
459            }
460        }
461    }
462
463    private boolean addReadBarrier(UnsafeLoadNode load) {
464        if (runtime.getConfig().useG1GC && load.graph().getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS && load.object().getKind() == Kind.Object && load.accessKind() == Kind.Object &&
465                        !StampTool.isPointerAlwaysNull(load.object())) {
466            ResolvedJavaType type = StampTool.typeOrNull(load.object());
467            if (type != null && !type.isArray()) {
468                return true;
469            }
470        }
471        return false;
472    }
473
474    private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, HotSpotResolvedJavaMethod method, ResolvedJavaType receiverType) {
475        return createReadVirtualMethod(graph, hub, method.vtableEntryOffset(receiverType));
476    }
477
478    private ReadNode createReadVirtualMethod(StructuredGraph graph, ValueNode hub, int vtableEntryOffset) {
479        assert vtableEntryOffset > 0;
480        // We use LocationNode.ANY_LOCATION for the reads that access the vtable
481        // entry as HotSpot does not guarantee that this is a final value.
482        Stamp methodStamp = MethodPointerStamp.method();
483        AddressNode address = createOffsetAddress(graph, hub, vtableEntryOffset);
484        ReadNode metaspaceMethod = graph.add(new ReadNode(address, any(), methodStamp, BarrierType.NONE));
485        return metaspaceMethod;
486    }
487
488    @Override
489    protected ValueNode createReadHub(StructuredGraph graph, ValueNode object, GuardingNode guard, LoweringTool tool) {
490        if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
491            return graph.unique(new LoadHubNode(tool.getStampProvider(), object, guard != null ? guard.asNode() : null));
492        }
493        HotSpotVMConfig config = runtime.getConfig();
494        assert !object.isConstant() || object.isNullConstant();
495
496        KlassPointerStamp hubStamp = (KlassPointerStamp) tool.getStampProvider().createHubStamp(true);
497        if (config.useCompressedClassPointers) {
498            hubStamp = hubStamp.compressed(config.getKlassEncoding());
499        }
500
501        AddressNode address = createOffsetAddress(graph, object, config.hubOffset);
502        FloatingReadNode memoryRead = graph.unique(new FloatingReadNode(address, HUB_LOCATION, null, hubStamp, guard, BarrierType.NONE));
503        if (config.useCompressedClassPointers) {
504            return CompressionNode.uncompress(memoryRead, config.getKlassEncoding());
505        } else {
506            return memoryRead;
507        }
508    }
509
510    private WriteNode createWriteHub(StructuredGraph graph, ValueNode object, ValueNode value) {
511        HotSpotVMConfig config = runtime.getConfig();
512        assert !object.isConstant() || object.asConstant().isDefaultForKind();
513
514        ValueNode writeValue = value;
515        if (config.useCompressedClassPointers) {
516            writeValue = CompressionNode.compress(value, config.getKlassEncoding());
517        }
518
519        AddressNode address = createOffsetAddress(graph, object, config.hubOffset);
520        return graph.add(new WriteNode(address, HUB_WRITE_LOCATION, writeValue, BarrierType.NONE));
521    }
522
523    @Override
524    protected BarrierType fieldLoadBarrierType(ResolvedJavaField f) {
525        HotSpotResolvedJavaField loadField = (HotSpotResolvedJavaField) f;
526        BarrierType barrierType = BarrierType.NONE;
527        if (runtime.getConfig().useG1GC && loadField.getKind() == Kind.Object && metaAccess.lookupJavaType(Reference.class).equals(loadField.getDeclaringClass()) &&
528                        loadField.getName().equals("referent")) {
529            barrierType = BarrierType.PRECISE;
530        }
531        return barrierType;
532    }
533
534    @Override
535    protected int fieldOffset(ResolvedJavaField f) {
536        HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) f;
537        return field.offset();
538    }
539
540    @Override
541    public int arrayScalingFactor(Kind kind) {
542        if (runtime.getConfig().useCompressedOops && kind == Kind.Object) {
543            return this.runtime.getTarget().getSizeInBytes(Kind.Int);
544        }
545        return super.arrayScalingFactor(kind);
546    }
547
548    @Override
549    protected int arrayBaseOffset(Kind kind) {
550        return runtime.getJVMCIRuntime().getArrayBaseOffset(kind);
551    }
552
553    @Override
554    protected int arrayLengthOffset() {
555        return runtime.getConfig().arrayLengthOffset;
556    }
557
558    @Override
559    protected LocationIdentity initLocationIdentity() {
560        return INIT_LOCATION;
561    }
562}