001/*
002 * Copyright (c) 2012, 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.replacements;
024
025import static com.oracle.graal.replacements.ReplacementsUtil.*;
026import static com.oracle.graal.compiler.common.GraalOptions.*;
027import static com.oracle.graal.hotspot.nodes.CStringNode.*;
028import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
029import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.Options.*;
030import static com.oracle.graal.nodes.PiArrayNode.*;
031import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
032import static com.oracle.graal.replacements.SnippetTemplate.*;
033import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*;
034import static jdk.internal.jvmci.code.UnsignedMath.*;
035import static jdk.internal.jvmci.hotspot.HotSpotMetaAccessProvider.*;
036import jdk.internal.jvmci.code.*;
037import jdk.internal.jvmci.common.*;
038
039import com.oracle.graal.debug.*;
040
041import jdk.internal.jvmci.hotspot.*;
042import jdk.internal.jvmci.meta.*;
043import jdk.internal.jvmci.options.*;
044
045import com.oracle.graal.api.replacements.*;
046import com.oracle.graal.compiler.common.spi.*;
047import com.oracle.graal.compiler.common.type.*;
048import com.oracle.graal.graph.Node.ConstantNodeParameter;
049import com.oracle.graal.graph.Node.NodeIntrinsic;
050import com.oracle.graal.hotspot.*;
051import com.oracle.graal.hotspot.meta.*;
052import com.oracle.graal.hotspot.nodes.*;
053import com.oracle.graal.hotspot.word.*;
054import com.oracle.graal.nodes.*;
055import com.oracle.graal.nodes.debug.*;
056import com.oracle.graal.nodes.extended.*;
057import com.oracle.graal.nodes.java.*;
058import com.oracle.graal.nodes.memory.address.*;
059import com.oracle.graal.nodes.spi.*;
060import com.oracle.graal.nodes.util.*;
061import com.oracle.graal.replacements.*;
062import com.oracle.graal.replacements.Snippet.ConstantParameter;
063import com.oracle.graal.replacements.Snippet.VarargsParameter;
064import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
065import com.oracle.graal.replacements.SnippetTemplate.Arguments;
066import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
067import com.oracle.graal.replacements.nodes.*;
068import com.oracle.graal.word.*;
069
070/**
071 * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY.
072 */
073public class NewObjectSnippets implements Snippets {
074
075    public static final LocationIdentity INIT_LOCATION = NamedLocationIdentity.mutable("Initialization");
076
077    static class Options {
078
079        //@formatter:off
080        @Option(help = "", type = OptionType.Debug)
081        static final OptionValue<Boolean> ProfileAllocations = new OptionValue<>(false);
082        //@formatter:on
083    }
084
085    static enum ProfileMode {
086        AllocatingMethods,
087        InstanceOrArray,
088        AllocatedTypes,
089        AllocatedTypesInMethods,
090        Total
091    }
092
093    public static final ProfileMode PROFILE_MODE = ProfileMode.AllocatedTypes;
094
095    @Fold
096    private static String createName(String path, String typeContext) {
097        switch (PROFILE_MODE) {
098            case AllocatingMethods:
099                return "";
100            case InstanceOrArray:
101                return path;
102            case AllocatedTypes:
103            case AllocatedTypesInMethods:
104                return typeContext;
105            case Total:
106                return "bytes";
107            default:
108                throw JVMCIError.shouldNotReachHere();
109        }
110    }
111
112    @Fold
113    private static boolean doProfile() {
114        return ProfileAllocations.getValue();
115    }
116
117    protected static void profileAllocation(String path, long size, String typeContext) {
118        if (doProfile()) {
119            String name = createName(path, typeContext);
120
121            boolean context = PROFILE_MODE == ProfileMode.AllocatingMethods || PROFILE_MODE == ProfileMode.AllocatedTypesInMethods;
122            DynamicCounterNode.counter(name, "number of bytes allocated", size, context);
123            DynamicCounterNode.counter(name, "number of allocations", 1, context);
124        }
125    }
126
127    public static void emitPrefetchAllocate(Word address, boolean isArray) {
128        if (config().allocatePrefetchStyle > 0) {
129            // Insert a prefetch for each allocation only on the fast-path
130            // Generate several prefetch instructions.
131            int lines = isArray ? config().allocatePrefetchLines : config().allocateInstancePrefetchLines;
132            int stepSize = config().allocatePrefetchStepSize;
133            int distance = config().allocatePrefetchDistance;
134            ExplodeLoopNode.explodeLoop();
135            for (int i = 0; i < lines; i++) {
136                PrefetchAllocateNode.prefetch(OffsetAddressNode.address(address, distance));
137                distance += stepSize;
138            }
139        }
140    }
141
142    @Snippet
143    public static Object allocateInstance(@ConstantParameter int size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
144                    @ConstantParameter boolean constantSize, @ConstantParameter String typeContext) {
145        Object result;
146        Word thread = registerAsWord(threadRegister);
147        Word top = readTlabTop(thread);
148        Word end = readTlabEnd(thread);
149        Word newTop = top.add(size);
150        if (useTLAB() && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
151            writeTlabTop(thread, newTop);
152            emitPrefetchAllocate(newTop, false);
153            result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, true);
154        } else {
155            new_stub.inc();
156            result = newInstance(HotSpotBackend.NEW_INSTANCE, hub);
157        }
158        profileAllocation("instance", size, typeContext);
159        return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
160    }
161
162    @NodeIntrinsic(ForeignCallNode.class)
163    public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
164
165    @Snippet
166    public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
167        if (probability(SLOW_PATH_PROBABILITY, type == null || DynamicNewInstanceNode.throwsInstantiationException(type))) {
168            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
169        }
170
171        KlassPointer hub = ClassGetHubNode.readClass(type);
172        if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
173            if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
174                int layoutHelper = readLayoutHelper(hub);
175                /*
176                 * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number,
177                 * the instance size. This size is already passed through align_object_size and
178                 * scaled to bytes. The low order bit is set if instances of this class cannot be
179                 * allocated using the fastpath.
180                 */
181                if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) {
182                    Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
183                    /*
184                     * FIXME(je,ds): we should actually pass typeContext instead of "" but late
185                     * binding of parameters is not yet supported by the GraphBuilderPlugin system.
186                     */
187                    return allocateInstance(layoutHelper, hub, prototypeMarkWord, fillContents, threadRegister, false, "");
188                }
189            }
190        }
191        return dynamicNewInstanceStub(type);
192    }
193
194    /**
195     * Maximum array length for which fast path allocation is used.
196     */
197    public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
198
199    @Snippet
200    public static Object allocateArray(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
201                    @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext) {
202        Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false);
203        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
204    }
205
206    private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents,
207                    @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, String typeContext, boolean skipNegativeCheck) {
208        Object result;
209        int alignment = wordSize();
210        int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
211        Word thread = registerAsWord(threadRegister);
212        Word top = readTlabTop(thread);
213        Word end = readTlabEnd(thread);
214        Word newTop = top.add(allocationSize);
215        if (probability(FREQUENT_PROBABILITY, skipNegativeCheck || belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB() &&
216                        probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
217            writeTlabTop(thread, newTop);
218            emitPrefetchAllocate(newTop, true);
219            newarray_loopInit.inc();
220            result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, true);
221        } else {
222            result = newArray(HotSpotBackend.NEW_ARRAY, hub, length);
223        }
224        profileAllocation("array", allocationSize, typeContext);
225        return result;
226    }
227
228    @NodeIntrinsic(ForeignCallNode.class)
229    public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
230
231    public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
232    public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
233
234    @NodeIntrinsic(ForeignCallNode.class)
235    public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType, int length);
236
237    public static Object dynamicNewInstanceStub(Class<?> elementType) {
238        return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType);
239    }
240
241    @NodeIntrinsic(ForeignCallNode.class)
242    public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
243
244    @Snippet
245    public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
246                    @ConstantParameter Kind knownElementKind, @ConstantParameter int knownLayoutHelper, Word prototypeMarkWord) {
247        Object result = allocateArrayDynamicImpl(elementType, length, fillContents, threadRegister, knownElementKind, knownLayoutHelper, prototypeMarkWord);
248        return result;
249    }
250
251    private static Object allocateArrayDynamicImpl(Class<?> elementType, int length, boolean fillContents, Register threadRegister, Kind knownElementKind, int knownLayoutHelper, Word prototypeMarkWord) {
252        /*
253         * We only need the dynamic check for void when we have no static information from
254         * knownElementKind.
255         */
256        staticAssert(knownElementKind != Kind.Void, "unsupported knownElementKind");
257        if (knownElementKind == Kind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType))) {
258            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
259        }
260
261        KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION);
262        if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, klass.isNull() || length < 0)) {
263            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
264        }
265        int layoutHelper = knownElementKind != Kind.Illegal ? knownLayoutHelper : readLayoutHelper(klass);
266        //@formatter:off
267        // from src/share/vm/oops/klass.hpp:
268        //
269        // For arrays, layout helper is a negative number, containing four
270        // distinct bytes, as follows:
271        //    MSB:[tag, hsz, ebt, log2(esz)]:LSB
272        // where:
273        //    tag is 0x80 if the elements are oops, 0xC0 if non-oops
274        //    hsz is array header size in bytes (i.e., offset of first element)
275        //    ebt is the BasicType of the elements
276        //    esz is the element size in bytes
277        //@formatter:on
278
279        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
280        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
281
282        Object result = allocateArrayImpl(klass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true);
283        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
284    }
285
286    /**
287     * Calls the runtime stub for implementing MULTIANEWARRAY.
288     */
289    @Snippet
290    public static Object newmultiarray(Word hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
291        Word dims = DimensionsNode.allocaDimsArray(rank);
292        ExplodeLoopNode.explodeLoop();
293        for (int i = 0; i < rank; i++) {
294            dims.writeInt(i * 4, dimensions[i], INIT_LOCATION);
295        }
296        return newArrayCall(HotSpotBackend.NEW_MULTI_ARRAY, hub, rank, dims);
297    }
298
299    @NodeIntrinsic(ForeignCallNode.class)
300    public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word hub, int rank, Word dims);
301
302    /**
303     * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
304     * objects have their bodies initialized in a loop.
305     */
306    private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8;
307
308    /**
309     * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring
310     * that stores are aligned.
311     *
312     * @param size number of bytes to zero
313     * @param memory beginning of object which is being zeroed
314     * @param constantSize is {@code size} known to be constant in the snippet
315     * @param startOffset offset to begin zeroing. May not be word aligned.
316     * @param manualUnroll maximally unroll zeroing
317     */
318    private static void zeroMemory(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
319        fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
320    }
321
322    private static void fillMemory(long value, int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
323        ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
324        int offset = startOffset;
325        if ((offset & 0x7) != 0) {
326            memory.writeInt(offset, (int) value, INIT_LOCATION);
327            offset += 4;
328        }
329        ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
330        if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
331            ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time");
332            // This case handles arrays of constant length. Instead of having a snippet variant for
333            // each length, generate a chain of stores of maximum length. Once it's inlined the
334            // break statement will trim excess stores.
335            if (useSnippetCounters) {
336                new_seqInit.inc();
337            }
338            explodeLoop();
339            for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) {
340                if (offset == size) {
341                    break;
342                }
343                memory.initializeLong(offset, value, INIT_LOCATION);
344            }
345        } else {
346            // Use Word instead of int to avoid extension to long in generated code
347            Word off = Word.signed(offset);
348            if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
349                if (useSnippetCounters) {
350                    new_seqInit.inc();
351                }
352                explodeLoop();
353            } else {
354                if (useSnippetCounters) {
355                    new_loopInit.inc();
356                }
357            }
358            for (; off.rawValue() < size; off = off.add(8)) {
359                memory.initializeLong(off, value, INIT_LOCATION);
360            }
361        }
362    }
363
364    /**
365     * Fill uninitialized memory with garbage value in a newly allocated object, unrolling as
366     * necessary and ensuring that stores are aligned.
367     *
368     * @param size number of bytes to zero
369     * @param memory beginning of object which is being zeroed
370     * @param constantSize is {@code  size} known to be constant in the snippet
371     * @param startOffset offset to begin zeroing. May not be word aligned.
372     * @param manualUnroll maximally unroll zeroing
373     */
374    private static void fillWithGarbage(int size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, boolean useSnippetCounters) {
375        fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, useSnippetCounters);
376    }
377
378    /**
379     * Formats some allocated memory with an object header and zeroes out the rest. Disables asserts
380     * since they can't be compiled in stubs.
381     */
382    public static Object formatObjectForStub(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord) {
383        return formatObject(hub, size, memory, compileTimePrototypeMarkWord, true, false, false);
384    }
385
386    /**
387     * Formats some allocated memory with an object header and zeroes out the rest.
388     */
389    protected static Object formatObject(KlassPointer hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, boolean useSnippetCounters) {
390        Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
391        initializeObjectHeader(memory, prototypeMarkWord, hub);
392        if (fillContents) {
393            zeroMemory(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
394        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
395            fillWithGarbage(size, memory, constantSize, instanceHeaderSize(), false, useSnippetCounters);
396        }
397        return memory.toObject();
398    }
399
400    @Snippet
401    protected static void verifyHeap(@ConstantParameter Register threadRegister) {
402        Word thread = registerAsWord(threadRegister);
403        Word topValue = readTlabTop(thread);
404        if (!topValue.equal(Word.zero())) {
405            Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION);
406            if (topValueContents.equal(Word.zero())) {
407                AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L);
408            }
409        }
410    }
411
412    /**
413     * Formats some allocated memory with an object header and zeroes out the rest.
414     */
415    public static Object formatArray(KlassPointer hub, int allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
416                    boolean useSnippetCounters) {
417        memory.writeInt(arrayLengthOffset(), length, INIT_LOCATION);
418        /*
419         * store hub last as the concurrent garbage collectors assume length is valid if hub field
420         * is not null
421         */
422        initializeObjectHeader(memory, prototypeMarkWord, hub);
423        if (fillContents) {
424            zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
425        } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
426            fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, useSnippetCounters);
427        }
428        return memory.toObject();
429    }
430
431    public static class Templates extends AbstractTemplates {
432
433        private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
434        private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
435        private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
436                        TLAB_END_LOCATION);
437        private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic", INIT_LOCATION, MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
438                        TLAB_END_LOCATION);
439        private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray", INIT_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
440        private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap");
441
442        public Templates(HotSpotProviders providers, TargetDescription target) {
443            super(providers, providers.getSnippetReflection(), target);
444        }
445
446        /**
447         * Lowers a {@link NewInstanceNode}.
448         */
449        public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
450            StructuredGraph graph = newInstanceNode.graph();
451            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
452            assert !type.isArray();
453            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), type.klass(), providers.getMetaAccess(), graph);
454            int size = instanceSize(type);
455
456            Arguments args = new Arguments(allocateInstance, graph.getGuardsStage(), tool.getLoweringStage());
457            args.addConst("size", size);
458            args.add("hub", hub);
459            args.add("prototypeMarkWord", type.prototypeMarkWord());
460            args.addConst("fillContents", newInstanceNode.fillContents());
461            args.addConst("threadRegister", registers.getThreadRegister());
462            args.addConst("constantSize", true);
463            args.addConst("typeContext", ProfileAllocations.getValue() ? type.toJavaName(false) : "");
464
465            SnippetTemplate template = template(args);
466            Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
467            template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
468        }
469
470        /**
471         * Lowers a {@link NewArrayNode}.
472         */
473        public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers, HotSpotGraalRuntimeProvider runtime, LoweringTool tool) {
474            StructuredGraph graph = newArrayNode.graph();
475            ResolvedJavaType elementType = newArrayNode.elementType();
476            HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
477            Kind elementKind = elementType.getKind();
478            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), arrayType.klass(), providers.getMetaAccess(), graph);
479            final int headerSize = runtime.getJVMCIRuntime().getArrayBaseOffset(elementKind);
480            HotSpotLoweringProvider lowerer = (HotSpotLoweringProvider) providers.getLowerer();
481            int log2ElementSize = CodeUtil.log2(lowerer.arrayScalingFactor(elementKind));
482
483            Arguments args = new Arguments(allocateArray, graph.getGuardsStage(), tool.getLoweringStage());
484            args.add("hub", hub);
485            ValueNode length = newArrayNode.length();
486            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
487            assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, Kind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord";
488            args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
489            args.addConst("headerSize", headerSize);
490            args.addConst("log2ElementSize", log2ElementSize);
491            args.addConst("fillContents", newArrayNode.fillContents());
492            args.addConst("threadRegister", registers.getThreadRegister());
493            args.addConst("maybeUnroll", length.isConstant());
494            args.addConst("typeContext", ProfileAllocations.getValue() ? arrayType.toJavaName(false) : "");
495
496            SnippetTemplate template = template(args);
497            Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
498            template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
499        }
500
501        public void lower(DynamicNewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
502            Arguments args = new Arguments(allocateInstanceDynamic, newInstanceNode.graph().getGuardsStage(), tool.getLoweringStage());
503            args.add("type", newInstanceNode.getInstanceType());
504            args.addConst("fillContents", newInstanceNode.fillContents());
505            args.addConst("threadRegister", registers.getThreadRegister());
506
507            SnippetTemplate template = template(args);
508            template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
509        }
510
511        public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
512            StructuredGraph graph = newArrayNode.graph();
513            Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage());
514            args.add("elementType", newArrayNode.getElementType());
515            ValueNode length = newArrayNode.length();
516            args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
517            args.addConst("fillContents", newArrayNode.fillContents());
518            args.addConst("threadRegister", registers.getThreadRegister());
519            /*
520             * We use Kind.Illegal as a marker value instead of null because constant snippet
521             * parameters cannot be null.
522             */
523            args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? Kind.Illegal : newArrayNode.getKnownElementKind());
524            if (newArrayNode.getKnownElementKind() != null) {
525                args.addConst("knownLayoutHelper", lookupArrayClass(tool, newArrayNode.getKnownElementKind()).layoutHelper());
526            } else {
527                args.addConst("knownLayoutHelper", 0);
528            }
529            args.add("prototypeMarkWord", lookupArrayClass(tool, Kind.Object).prototypeMarkWord());
530            SnippetTemplate template = template(args);
531            template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
532        }
533
534        private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, Kind kind) {
535            return (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(kind == Kind.Object ? Object.class : kind.toJavaClass()).getArrayClass();
536        }
537
538        public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
539            StructuredGraph graph = newmultiarrayNode.graph();
540            int rank = newmultiarrayNode.dimensionCount();
541            ValueNode[] dims = new ValueNode[rank];
542            for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) {
543                dims[i] = newmultiarrayNode.dimension(i);
544            }
545            HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type();
546            ConstantNode hub = ConstantNode.forConstant(tool.getStampProvider().createHubStamp(true), type.klass(), providers.getMetaAccess(), graph);
547
548            Arguments args = new Arguments(newmultiarray, graph.getGuardsStage(), tool.getLoweringStage());
549            args.add("hub", hub);
550            args.addConst("rank", rank);
551            args.addVarargs("dimensions", int.class, StampFactory.forKind(Kind.Int), dims);
552            template(args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
553        }
554
555        private static int instanceSize(HotSpotResolvedObjectType type) {
556            int size = type.instanceSize();
557            assert size >= 0;
558            return size;
559        }
560
561        public void lower(VerifyHeapNode verifyHeapNode, HotSpotRegistersProvider registers, HotSpotGraalRuntimeProvider runtime, LoweringTool tool) {
562            if (runtime.getConfig().cAssertions) {
563                Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
564                args.addConst("threadRegister", registers.getThreadRegister());
565
566                SnippetTemplate template = template(args);
567                template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
568            } else {
569                GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);
570            }
571        }
572    }
573
574    private static final SnippetCounter.Group countersNew = SnippetCounters.getValue() ? new SnippetCounter.Group("NewInstance") : null;
575    private static final SnippetCounter new_seqInit = new SnippetCounter(countersNew, "tlabSeqInit", "TLAB alloc with unrolled zeroing");
576    private static final SnippetCounter new_loopInit = new SnippetCounter(countersNew, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
577    private static final SnippetCounter new_stub = new SnippetCounter(countersNew, "stub", "alloc and zeroing via stub");
578
579    private static final SnippetCounter.Group countersNewArray = SnippetCounters.getValue() ? new SnippetCounter.Group("NewArray") : null;
580    private static final SnippetCounter newarray_loopInit = new SnippetCounter(countersNewArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
581    private static final SnippetCounter newarray_stub = new SnippetCounter(countersNewArray, "stub", "alloc and zeroing via stub");
582}