1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.hotspot.replacements;
  26 
  27 import static jdk.vm.ci.meta.DeoptimizationAction.None;
  28 import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
  29 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  30 import static org.graalvm.compiler.core.common.GraalOptions.MinimalBulkZeroingSize;
  31 import static org.graalvm.compiler.core.common.calc.UnsignedMath.belowThan;
  32 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_OPTIONVALUES;
  33 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
  34 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY;
  35 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_ARRAY_OR_NULL;
  36 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE;
  37 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_INSTANCE_OR_NULL;
  38 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY;
  39 import static org.graalvm.compiler.hotspot.HotSpotBackend.NEW_MULTI_ARRAY_OR_NULL;
  40 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION;
  41 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_STATE_LOCATION;
  42 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_WRITE_LOCATION;
  43 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
  44 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
  45 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION;
  46 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION;
  47 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.allocateInstancePrefetchLines;
  48 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.allocatePrefetchDistance;
  49 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.allocatePrefetchLines;
  50 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.allocatePrefetchStepSize;
  51 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.allocatePrefetchStyle;
  52 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayAllocationSize;
  53 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset;
  54 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayLengthOffset;
  55 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.initializeObjectHeader;
  56 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.instanceHeaderSize;
  57 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.isInstanceKlassFullyInitialized;
  58 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
  59 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
  60 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
  61 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
  62 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject;
  63 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
  64 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
  65 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabEnd;
  66 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readTlabTop;
  67 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
  68 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking;
  69 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB;
  70 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
  71 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop;
  72 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocations;
  73 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocationsContext;
  74 import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCastToSnippetReplaceeStamp;
  75 import static org.graalvm.compiler.nodes.PiNode.piCastToSnippetReplaceeStamp;
  76 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
  77 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
  78 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
  79 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
  80 import static org.graalvm.compiler.replacements.ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED;
  81 import static org.graalvm.compiler.replacements.ReplacementsUtil.runtimeAssert;
  82 import static org.graalvm.compiler.replacements.ReplacementsUtil.staticAssert;
  83 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
  84 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
  85 import static org.graalvm.compiler.replacements.nodes.ExplodeLoopNode.explodeLoop;
  86 
  87 import org.graalvm.compiler.api.replacements.Fold;
  88 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
  89 import org.graalvm.compiler.api.replacements.Snippet;
  90 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
  91 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
  92 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  93 import org.graalvm.compiler.core.common.type.StampFactory;
  94 import org.graalvm.compiler.debug.DebugHandlersFactory;
  95 import org.graalvm.compiler.debug.GraalError;
  96 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  97 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  98 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  99 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 100 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
 101 import org.graalvm.compiler.hotspot.nodes.DimensionsNode;
 102 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
 103 import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
 104 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
 105 import org.graalvm.compiler.hotspot.word.KlassPointer;
 106 import org.graalvm.compiler.nodes.ConstantNode;
 107 import org.graalvm.compiler.nodes.DeoptimizeNode;
 108 import org.graalvm.compiler.nodes.PiNode;
 109 import org.graalvm.compiler.nodes.PrefetchAllocateNode;
 110 import org.graalvm.compiler.nodes.SnippetAnchorNode;
 111 import org.graalvm.compiler.nodes.StructuredGraph;
 112 import org.graalvm.compiler.nodes.ValueNode;
 113 import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
 114 import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
 115 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 116 import org.graalvm.compiler.nodes.extended.MembarNode;
 117 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
 118 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode;
 119 import org.graalvm.compiler.nodes.java.NewArrayNode;
 120 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 121 import org.graalvm.compiler.nodes.java.NewMultiArrayNode;
 122 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 123 import org.graalvm.compiler.nodes.spi.LoweringTool;
 124 import org.graalvm.compiler.nodes.util.GraphUtil;
 125 import org.graalvm.compiler.options.OptionValues;
 126 import org.graalvm.compiler.replacements.ReplacementsUtil;
 127 import org.graalvm.compiler.replacements.SnippetCounter;
 128 import org.graalvm.compiler.replacements.SnippetCounter.Group;
 129 import org.graalvm.compiler.replacements.SnippetTemplate;
 130 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
 131 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
 132 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
 133 import org.graalvm.compiler.replacements.Snippets;
 134 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 135 import org.graalvm.compiler.replacements.nodes.ZeroMemoryNode;
 136 import org.graalvm.compiler.word.Word;
 137 import jdk.internal.vm.compiler.word.LocationIdentity;
 138 import jdk.internal.vm.compiler.word.WordFactory;
 139 
 140 import jdk.vm.ci.code.CodeUtil;
 141 import jdk.vm.ci.code.MemoryBarriers;
 142 import jdk.vm.ci.code.Register;
 143 import jdk.vm.ci.code.TargetDescription;
 144 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
 145 import jdk.vm.ci.meta.JavaKind;
 146 import jdk.vm.ci.meta.ResolvedJavaType;
 147 
 148 /**
 149  * Snippets used for implementing NEW, ANEWARRAY and NEWARRAY.
 150  */
 151 public class NewObjectSnippets implements Snippets {
 152 
 153     enum ProfileContext {
 154         AllocatingMethod,
 155         InstanceOrArray,
 156         AllocatedType,
 157         AllocatedTypesInMethod,
 158         Total
 159     }
 160 
 161     @Fold
 162     static String createName(@Fold.InjectedParameter OptionValues options, String path, String typeContext) {
 163         switch (ProfileAllocationsContext.getValue(options)) {
 164             case AllocatingMethod:
 165                 return "";
 166             case InstanceOrArray:
 167                 return path;
 168             case AllocatedType:
 169             case AllocatedTypesInMethod:
 170                 return typeContext;
 171             case Total:
 172                 return "bytes";
 173             default:
 174                 throw GraalError.shouldNotReachHere();
 175         }
 176     }
 177 
 178     @Fold
 179     static boolean doProfile(@Fold.InjectedParameter OptionValues options) {
 180         return ProfileAllocations.getValue(options);
 181     }
 182 
 183     @Fold
 184     static boolean withContext(@Fold.InjectedParameter OptionValues options) {
 185         ProfileContext context = ProfileAllocationsContext.getValue(options);
 186         return context == ProfileContext.AllocatingMethod || context == ProfileContext.AllocatedTypesInMethod;
 187     }
 188 
 189     protected static void profileAllocation(String path, long size, String typeContext) {
 190         if (doProfile(INJECTED_OPTIONVALUES)) {
 191             String name = createName(INJECTED_OPTIONVALUES, path, typeContext);
 192 
 193             boolean context = withContext(INJECTED_OPTIONVALUES);
 194             DynamicCounterNode.counter("number of bytes allocated", name, size, context);
 195             DynamicCounterNode.counter("number of allocations", name, 1, context);
 196         }
 197     }
 198 
 199     public static void emitPrefetchAllocate(Word address, boolean isArray) {
 200         if (allocatePrefetchStyle(INJECTED_VMCONFIG) > 0) {
 201             // Insert a prefetch for each allocation only on the fast-path
 202             // Generate several prefetch instructions.
 203             int lines = isArray ? allocatePrefetchLines(INJECTED_VMCONFIG) : allocateInstancePrefetchLines(INJECTED_VMCONFIG);
 204             int stepSize = allocatePrefetchStepSize(INJECTED_VMCONFIG);
 205             int distance = allocatePrefetchDistance(INJECTED_VMCONFIG);
 206             ExplodeLoopNode.explodeLoop();
 207             for (int i = 0; i < lines; i++) {
 208                 PrefetchAllocateNode.prefetch(OffsetAddressNode.address(address, distance));
 209                 distance += stepSize;
 210             }
 211         }
 212     }
 213 
 214     @Snippet
 215     public static Object allocateInstance(@ConstantParameter long size,
 216                     KlassPointer hub,
 217                     Word prototypeMarkWord,
 218                     @ConstantParameter boolean fillContents,
 219                     @ConstantParameter boolean emitMemoryBarrier,
 220                     @ConstantParameter Register threadRegister,
 221                     @ConstantParameter boolean constantSize,
 222                     @ConstantParameter String typeContext,
 223                     @ConstantParameter Counters counters) {
 224         return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, hub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, constantSize, typeContext, counters));
 225     }
 226 
 227     public static Object allocateInstanceHelper(long size,
 228                     KlassPointer hub,
 229                     Word prototypeMarkWord,
 230                     boolean fillContents,
 231                     boolean emitMemoryBarrier,
 232                     Register threadRegister,
 233                     boolean constantSize,
 234                     String typeContext,
 235                     Counters counters) {
 236         Object result;
 237         Word thread = registerAsWord(threadRegister);
 238         Word top = readTlabTop(thread);
 239         Word end = readTlabEnd(thread);
 240         Word newTop = top.add(WordFactory.unsigned(size));
 241         if (useTLAB(INJECTED_VMCONFIG) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
 242             writeTlabTop(thread, newTop);
 243             emitPrefetchAllocate(newTop, false);
 244             result = formatObject(hub, size, top, prototypeMarkWord, fillContents, emitMemoryBarrier, constantSize, counters);
 245         } else {
 246             Counters theCounters = counters;
 247             if (theCounters != null && theCounters.stub != null) {
 248                 theCounters.stub.inc();
 249             }
 250             result = newInstanceStub(hub);
 251         }
 252         profileAllocation("instance", size, typeContext);
 253         return verifyOop(result);
 254     }
 255 
 256     public static Object newInstanceStub(KlassPointer hub) {
 257         if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
 258             return nonNullOrDeopt(newInstanceOrNull(NEW_INSTANCE_OR_NULL, hub));
 259         } else {
 260             return newInstance(NEW_INSTANCE, hub);
 261         }
 262     }
 263 
 264     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
 265     private static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 266 
 267     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
 268     private static native Object newInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
 269 
 270     @Snippet
 271     public static Object allocateInstancePIC(@ConstantParameter long size,
 272                     KlassPointer hub,
 273                     Word prototypeMarkWord,
 274                     @ConstantParameter boolean fillContents,
 275                     @ConstantParameter boolean emitMemoryBarrier,
 276                     @ConstantParameter Register threadRegister,
 277                     @ConstantParameter boolean constantSize,
 278                     @ConstantParameter String typeContext,
 279                     @ConstantParameter Counters counters) {
 280         // Klass must be initialized by the time the first instance is allocated, therefore we can
 281         // just load it from the corresponding cell and avoid the resolution check. We have to use a
 282         // fixed load though, to prevent it from floating above the initialization.
 283         KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
 284         return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, picHub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, constantSize, typeContext, counters));
 285     }
 286 
 287     @Snippet
 288     public static Object allocateInstanceDynamic(Class<?> type, Class<?> classClass,
 289                     @ConstantParameter boolean fillContents,
 290                     @ConstantParameter boolean emitMemoryBarrier,
 291                     @ConstantParameter Register threadRegister,
 292                     @ConstantParameter Counters counters) {
 293         if (probability(SLOW_PATH_PROBABILITY, type == null)) {
 294             DeoptimizeNode.deopt(None, RuntimeConstraint);
 295         }
 296         Class<?> nonNullType = PiNode.piCastNonNullClass(type, SnippetAnchorNode.anchor());
 297 
 298         if (probability(SLOW_PATH_PROBABILITY, DynamicNewInstanceNode.throwsInstantiationException(type, classClass))) {
 299             DeoptimizeNode.deopt(None, RuntimeConstraint);
 300         }
 301 
 302         return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(type, fillContents, emitMemoryBarrier, threadRegister, counters, nonNullType));
 303     }
 304 
 305     private static Object allocateInstanceDynamicHelper(Class<?> type,
 306                     boolean fillContents,
 307                     boolean emitMemoryBarrier,
 308                     Register threadRegister,
 309                     Counters counters,
 310                     Class<?> nonNullType) {
 311         KlassPointer hub = ClassGetHubNode.readClass(nonNullType);
 312         if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
 313             KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor());
 314 
 315             if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(nonNullHub))) {
 316                 int layoutHelper = readLayoutHelper(nonNullHub);
 317                 /*
 318                  * src/share/vm/oops/klass.hpp: For instances, layout helper is a positive number,
 319                  * the instance size. This size is already passed through align_object_size and
 320                  * scaled to bytes. The low order bit is set if instances of this class cannot be
 321                  * allocated using the fastpath.
 322                  */
 323                 if (probability(FAST_PATH_PROBABILITY, (layoutHelper & 1) == 0)) {
 324                     Word prototypeMarkWord = nonNullHub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
 325                     /*
 326                      * FIXME(je,ds): we should actually pass typeContext instead of "" but late
 327                      * binding of parameters is not yet supported by the GraphBuilderPlugin system.
 328                      */
 329                     return allocateInstanceHelper(layoutHelper, nonNullHub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, false, "", counters);
 330                 }
 331             } else {
 332                 DeoptimizeNode.deopt(None, RuntimeConstraint);
 333             }
 334         }
 335         return dynamicNewInstanceStub(type);
 336     }
 337 
 338     /**
 339      * Maximum array length for which fast path allocation is used.
 340      */
 341     public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
 342 
 343     @Snippet
 344     public static Object allocatePrimitiveArrayPIC(KlassPointer hub,
 345                     int length,
 346                     Word prototypeMarkWord,
 347                     @ConstantParameter int headerSize,
 348                     @ConstantParameter int log2ElementSize,
 349                     @ConstantParameter boolean fillContents,
 350                     @ConstantParameter boolean emitMemoryBarrier,
 351                     @ConstantParameter Register threadRegister,
 352                     @ConstantParameter boolean maybeUnroll,
 353                     @ConstantParameter String typeContext,
 354                     @ConstantParameter boolean useBulkZeroing,
 355                     @ConstantParameter Counters counters) {
 356         // Primitive array types are eagerly pre-resolved. We can use a floating load.
 357         KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub);
 358         return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
 359                         emitMemoryBarrier, threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
 360     }
 361 
 362     @Snippet
 363     public static Object allocateArrayPIC(KlassPointer hub,
 364                     int length,
 365                     Word prototypeMarkWord,
 366                     @ConstantParameter int headerSize,
 367                     @ConstantParameter int log2ElementSize,
 368                     @ConstantParameter boolean fillContents,
 369                     @ConstantParameter boolean emitMemoryBarrier,
 370                     @ConstantParameter Register threadRegister,
 371                     @ConstantParameter boolean maybeUnroll,
 372                     @ConstantParameter String typeContext,
 373                     @ConstantParameter boolean useBulkZeroing,
 374                     @ConstantParameter Counters counters) {
 375         // Array type would be resolved by dominating resolution.
 376         KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
 377         return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
 378                         emitMemoryBarrier, threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
 379     }
 380 
 381     @Snippet
 382     public static Object allocateArray(KlassPointer hub,
 383                     int length,
 384                     Word prototypeMarkWord,
 385                     @ConstantParameter int headerSize,
 386                     @ConstantParameter int log2ElementSize,
 387                     @ConstantParameter boolean fillContents,
 388                     @ConstantParameter boolean emitMemoryBarrier,
 389                     @ConstantParameter Register threadRegister,
 390                     @ConstantParameter boolean maybeUnroll,
 391                     @ConstantParameter String typeContext,
 392                     @ConstantParameter boolean useBulkZeroing,
 393                     @ConstantParameter Counters counters) {
 394         Object result = allocateArrayImpl(hub,
 395                         length,
 396                         prototypeMarkWord,
 397                         headerSize,
 398                         log2ElementSize,
 399                         fillContents,
 400                         emitMemoryBarrier, threadRegister,
 401                         maybeUnroll,
 402                         typeContext,
 403                         useBulkZeroing,
 404                         counters);
 405         return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
 406     }
 407 
 408     /**
 409      * When allocating on the slow path, determines whether to use a version of the runtime call
 410      * that returns {@code null} on a failed allocation instead of raising an OutOfMemoryError.
 411      */
 412     @Fold
 413     static boolean useNullAllocationStubs(@InjectedParameter GraalHotSpotVMConfig config) {
 414         return config.areNullAllocationStubsAvailable();
 415     }
 416 
 417     private static Object allocateArrayImpl(KlassPointer hub,
 418                     int length,
 419                     Word prototypeMarkWord,
 420                     int headerSize,
 421                     int log2ElementSize,
 422                     boolean fillContents,
 423                     boolean emitMemoryBarrier,
 424                     Register threadRegister,
 425                     boolean maybeUnroll,
 426                     String typeContext,
 427                     boolean useBulkZeroing,
 428                     Counters counters) {
 429         Object result;
 430         long allocationSize = arrayAllocationSize(length, headerSize, log2ElementSize);
 431         Word thread = registerAsWord(threadRegister);
 432         Word top = readTlabTop(thread);
 433         Word end = readTlabEnd(thread);
 434         Word newTop = top.add(WordFactory.unsigned(allocationSize));
 435         if (probability(FREQUENT_PROBABILITY, belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) && useTLAB(INJECTED_VMCONFIG) &&
 436                         probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
 437             writeTlabTop(thread, newTop);
 438             emitPrefetchAllocate(newTop, true);
 439             Counters theCounters = counters;
 440             if (theCounters != null && theCounters.arrayLoopInit != null) {
 441                 theCounters.arrayLoopInit.inc();
 442             }
 443             result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, emitMemoryBarrier, maybeUnroll, useBulkZeroing, counters);
 444         } else {
 445             result = newArrayStub(hub, length);
 446         }
 447         profileAllocation("array", allocationSize, typeContext);
 448         return result;
 449     }
 450 
 451     public static Object newArrayStub(KlassPointer hub, int length) {
 452         if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
 453             return nonNullOrDeopt(newArrayOrNull(NEW_ARRAY_OR_NULL, hub, length));
 454         } else {
 455             return newArray(NEW_ARRAY, hub, length);
 456         }
 457     }
 458 
 459     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
 460     private static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
 461 
 462     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
 463     private static native Object newArrayOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length);
 464 
 465     /**
 466      * New dynamic array stub that throws an {@link OutOfMemoryError} on allocation failure.
 467      */
 468     public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class);
 469 
 470     /**
 471      * New dynamic array stub that returns null on allocation failure.
 472      */
 473     public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE_OR_NULL = new ForeignCallDescriptor("dynamic_new_instance_or_null", Object.class, Class.class);
 474 
 475     public static Object dynamicNewInstanceStub(Class<?> elementType) {
 476         if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
 477             return nonNullOrDeopt(dynamicNewInstanceOrNull(DYNAMIC_NEW_INSTANCE_OR_NULL, elementType));
 478         } else {
 479             return dynamicNewInstance(DYNAMIC_NEW_INSTANCE, elementType);
 480         }
 481     }
 482 
 483     /**
 484      * Deoptimizes if {@code obj == null} otherwise returns {@code obj}.
 485      */
 486     private static Object nonNullOrDeopt(Object obj) {
 487         if (obj == null) {
 488             DeoptimizeNode.deopt(None, RuntimeConstraint);
 489         }
 490         return obj;
 491     }
 492 
 493     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
 494     public static native Object dynamicNewInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 495 
 496     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
 497     public static native Object dynamicNewInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 498 
 499     @Snippet
 500     public static Object allocateArrayDynamic(Class<?> elementType,
 501                     Class<?> voidClass,
 502                     int length,
 503                     @ConstantParameter boolean fillContents,
 504                     @ConstantParameter boolean emitMemoryBarrier,
 505                     @ConstantParameter Register threadRegister,
 506                     @ConstantParameter JavaKind knownElementKind,
 507                     @ConstantParameter int knownLayoutHelper,
 508                     @ConstantParameter boolean useBulkZeroing,
 509                     Word prototypeMarkWord,
 510                     @ConstantParameter Counters counters) {
 511         Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, emitMemoryBarrier, threadRegister, knownElementKind,
 512                         knownLayoutHelper, useBulkZeroing, prototypeMarkWord, counters);
 513         return result;
 514     }
 515 
 516     private static Object allocateArrayDynamicImpl(Class<?> elementType,
 517                     Class<?> voidClass,
 518                     int length,
 519                     boolean fillContents,
 520                     boolean emitMemoryBarrier,
 521                     Register threadRegister,
 522                     JavaKind knownElementKind,
 523                     int knownLayoutHelper,
 524                     boolean useBulkZeroing,
 525                     Word prototypeMarkWord,
 526                     Counters counters) {
 527         /*
 528          * We only need the dynamic check for void when we have no static information from
 529          * knownElementKind.
 530          */
 531         staticAssert(knownElementKind != JavaKind.Void, "unsupported knownElementKind");
 532         if (knownElementKind == JavaKind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType, voidClass))) {
 533             DeoptimizeNode.deopt(None, RuntimeConstraint);
 534         }
 535 
 536         KlassPointer klass = loadKlassFromObject(elementType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION);
 537         if (klass.isNull()) {
 538             DeoptimizeNode.deopt(None, RuntimeConstraint);
 539         }
 540         KlassPointer nonNullKlass = ClassGetHubNode.piCastNonNull(klass, SnippetAnchorNode.anchor());
 541 
 542         if (length < 0) {
 543             DeoptimizeNode.deopt(None, RuntimeConstraint);
 544         }
 545         int layoutHelper;
 546         if (knownElementKind == JavaKind.Illegal) {
 547             layoutHelper = readLayoutHelper(nonNullKlass);
 548         } else {
 549             runtimeAssert(knownLayoutHelper == readLayoutHelper(nonNullKlass), "layout mismatch");
 550             layoutHelper = knownLayoutHelper;
 551         }
 552         //@formatter:off
 553         // from src/share/vm/oops/klass.hpp:
 554         //
 555         // For arrays, layout helper is a negative number, containing four
 556         // distinct bytes, as follows:
 557         //    MSB:[tag, hsz, ebt, log2(esz)]:LSB
 558         // where:
 559         //    tag is 0x80 if the elements are oops, 0xC0 if non-oops
 560         //    hsz is array header size in bytes (i.e., offset of first element)
 561         //    ebt is the BasicType of the elements
 562         //    esz is the element size in bytes
 563         //@formatter:on
 564 
 565         int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
 566         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
 567 
 568         Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
 569                         emitMemoryBarrier, threadRegister, false, "dynamic type", useBulkZeroing, counters);
 570         return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
 571     }
 572 
 573     /**
 574      * Calls the runtime stub for implementing MULTIANEWARRAY.
 575      */
 576     @Snippet
 577     private static Object newmultiarray(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
 578         Word dims = DimensionsNode.allocaDimsArray(rank);
 579         ExplodeLoopNode.explodeLoop();
 580         for (int i = 0; i < rank; i++) {
 581             dims.writeInt(i * 4, dimensions[i], LocationIdentity.init());
 582         }
 583         return newMultiArrayStub(hub, rank, dims);
 584     }
 585 
 586     private static Object newMultiArrayStub(KlassPointer hub, int rank, Word dims) {
 587         if (useNullAllocationStubs(INJECTED_VMCONFIG)) {
 588             return nonNullOrDeopt(newMultiArrayOrNull(NEW_MULTI_ARRAY_OR_NULL, hub, rank, dims));
 589         } else {
 590             return newMultiArray(NEW_MULTI_ARRAY, hub, rank, dims);
 591         }
 592     }
 593 
 594     @Snippet
 595     private static Object newmultiarrayPIC(KlassPointer hub, @ConstantParameter int rank, @VarargsParameter int[] dimensions) {
 596         // Array type would be resolved by dominating resolution.
 597         KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
 598         return newmultiarray(picHub, rank, dimensions);
 599     }
 600 
 601     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true)
 602     private static native Object newMultiArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
 603 
 604     @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false)
 605     private static native Object newMultiArrayOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims);
 606 
 607     /**
 608      * Maximum number of long stores to emit when zeroing an object with a constant size. Larger
 609      * objects have their bodies initialized in a loop.
 610      */
 611     private static final int MAX_UNROLLED_OBJECT_ZEROING_STORES = 8;
 612 
 613     /**
 614      * Zero uninitialized memory in a newly allocated object, unrolling as necessary and ensuring
 615      * that stores are aligned.
 616      *
 617      * @param size number of bytes to zero
 618      * @param memory beginning of object which is being zeroed
 619      * @param constantSize is {@code size} known to be constant in the snippet
 620      * @param startOffset offset to begin zeroing. May not be word aligned.
 621      * @param manualUnroll maximally unroll zeroing
 622      * @param useBulkZeroing apply bulk zeroing
 623      */
 624     private static void zeroMemory(long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll,
 625                     boolean useBulkZeroing, Counters counters) {
 626         fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useBulkZeroing, counters);
 627     }
 628 
 629     private static void fillMemory(long value, long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll,
 630                     boolean useBulkZeroing, Counters counters) {
 631         ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
 632         int offset = startOffset;
 633         if ((offset & 0x7) != 0) {
 634             memory.writeInt(offset, (int) value, LocationIdentity.init());
 635             offset += 4;
 636         }
 637         ReplacementsUtil.runtimeAssert((offset & 0x7) == 0, "unaligned offset");
 638         Counters theCounters = counters;
 639         if (manualUnroll && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
 640             ReplacementsUtil.staticAssert(!constantSize, "size shouldn't be constant at instantiation time");
 641             // This case handles arrays of constant length. Instead of having a snippet variant for
 642             // each length, generate a chain of stores of maximum length. Once it's inlined the
 643             // break statement will trim excess stores.
 644             if (theCounters != null && theCounters.instanceSeqInit != null) {
 645                 theCounters.instanceSeqInit.inc();
 646             }
 647 
 648             explodeLoop();
 649             for (int i = 0; i < MAX_UNROLLED_OBJECT_ZEROING_STORES; i++, offset += 8) {
 650                 if (offset == size) {
 651                     break;
 652                 }
 653                 memory.initializeLong(offset, value, LocationIdentity.init());
 654             }
 655         } else {
 656             // Use Word instead of int to avoid extension to long in generated code
 657             Word off = WordFactory.signed(offset);
 658             if (useBulkZeroing && value == 0 && probability(SLOW_PATH_PROBABILITY, (size - offset) >= getMinimalBulkZeroingSize(INJECTED_OPTIONVALUES))) {
 659                 if (theCounters != null && theCounters.instanceBulkInit != null) {
 660                     theCounters.instanceBulkInit.inc();
 661                 }
 662                 ZeroMemoryNode.zero(memory.add(off), size - offset, LocationIdentity.init());
 663             } else {
 664                 if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
 665                     if (theCounters != null && theCounters.instanceSeqInit != null) {
 666                         theCounters.instanceSeqInit.inc();
 667                     }
 668                     explodeLoop();
 669                 } else {
 670                     if (theCounters != null && theCounters.instanceLoopInit != null) {
 671                         theCounters.instanceLoopInit.inc();
 672                     }
 673                 }
 674                 for (; off.rawValue() < size; off = off.add(8)) {
 675                     memory.initializeLong(off, value, LocationIdentity.init());
 676                 }
 677             }
 678         }
 679     }
 680 
 681     @Fold
 682     static int getMinimalBulkZeroingSize(@InjectedParameter OptionValues optionValues) {
 683         return MinimalBulkZeroingSize.getValue(optionValues);
 684     }
 685 
 686     /**
 687      * Fill uninitialized memory with garbage value in a newly allocated object, unrolling as
 688      * necessary and ensuring that stores are aligned.
 689      *
 690      * @param size number of bytes to zero
 691      * @param memory beginning of object which is being zeroed
 692      * @param constantSize is {@code  size} known to be constant in the snippet
 693      * @param startOffset offset to begin zeroing. May not be word aligned.
 694      * @param manualUnroll maximally unroll zeroing
 695      */
 696     private static void fillWithGarbage(long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, Counters counters) {
 697         fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, false, counters);
 698     }
 699 
 700     /**
 701      * Formats some allocated memory with an object header and zeroes out the rest.
 702      */
 703     private static Object formatObject(KlassPointer hub,
 704                     long size,
 705                     Word memory,
 706                     Word compileTimePrototypeMarkWord,
 707                     boolean fillContents,
 708                     boolean emitMemoryBarrier,
 709                     boolean constantSize,
 710                     Counters counters) {
 711         Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
 712         initializeObjectHeader(memory, prototypeMarkWord, hub);
 713         if (fillContents) {
 714             zeroMemory(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, false, counters);
 715         } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
 716             fillWithGarbage(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, counters);
 717         }
 718         if (emitMemoryBarrier) {
 719             MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
 720         }
 721         return memory.toObjectNonNull();
 722     }
 723 
 724     @Snippet
 725     private static void verifyHeap(@ConstantParameter Register threadRegister) {
 726         Word thread = registerAsWord(threadRegister);
 727         Word topValue = readTlabTop(thread);
 728         if (!topValue.equal(WordFactory.zero())) {
 729             Word topValueContents = topValue.readWord(0, MARK_WORD_LOCATION);
 730             if (topValueContents.equal(WordFactory.zero())) {
 731                 AssertionSnippets.vmMessageC(AssertionSnippets.ASSERTION_VM_MESSAGE_C, true, cstring("overzeroing of TLAB detected"), 0L, 0L, 0L);
 732             }
 733         }
 734     }
 735 
 736     /**
 737      * Formats some allocated memory with an object header and zeroes out the rest.
 738      */
 739     private static Object formatArray(KlassPointer hub,
 740                     long allocationSize,
 741                     int length,
 742                     int headerSize,
 743                     Word memory,
 744                     Word prototypeMarkWord,
 745                     boolean fillContents,
 746                     boolean emitMemoryBarrier,
 747                     boolean maybeUnroll,
 748                     boolean useBulkZeroing,
 749                     Counters counters) {
 750         memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, LocationIdentity.init());
 751         /*
 752          * store hub last as the concurrent garbage collectors assume length is valid if hub field
 753          * is not null
 754          */
 755         initializeObjectHeader(memory, prototypeMarkWord, hub);
 756         if (fillContents) {
 757             zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useBulkZeroing, counters);
 758         } else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
 759             fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, counters);
 760         }
 761         if (emitMemoryBarrier) {
 762             MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
 763         }
 764         return memory.toObjectNonNull();
 765     }
 766 
 767     static class Counters {
 768         Counters(SnippetCounter.Group.Factory factory) {
 769             Group newInstance = factory.createSnippetCounterGroup("NewInstance");
 770             Group newArray = factory.createSnippetCounterGroup("NewArray");
 771             instanceSeqInit = new SnippetCounter(newInstance, "tlabSeqInit", "TLAB alloc with unrolled zeroing");
 772             instanceLoopInit = new SnippetCounter(newInstance, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
 773             instanceBulkInit = new SnippetCounter(newArray, "tlabBulkInit", "TLAB alloc with bulk zeroing");
 774             arrayLoopInit = new SnippetCounter(newArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
 775             stub = new SnippetCounter(newInstance, "stub", "alloc and zeroing via stub");
 776         }
 777 
 778         final SnippetCounter instanceSeqInit;
 779         final SnippetCounter instanceLoopInit;
 780         final SnippetCounter instanceBulkInit;
 781         final SnippetCounter arrayLoopInit;
 782         final SnippetCounter stub;
 783     }
 784 
 785     public static class Templates extends AbstractTemplates {
 786 
 787         private final SnippetInfo allocateInstance = snippet(NewObjectSnippets.class, "allocateInstance", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION,
 788                         PROTOTYPE_MARK_WORD_LOCATION);
 789         private final SnippetInfo allocateInstancePIC = snippet(NewObjectSnippets.class, "allocateInstancePIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
 790                         TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION);
 791         private final SnippetInfo allocateArray = snippet(NewObjectSnippets.class, "allocateArray", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
 792         private final SnippetInfo allocateArrayPIC = snippet(NewObjectSnippets.class, "allocateArrayPIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION, TLAB_END_LOCATION);
 793         private final SnippetInfo allocatePrimitiveArrayPIC = snippet(NewObjectSnippets.class, "allocatePrimitiveArrayPIC", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
 794                         TLAB_END_LOCATION);
 795         private final SnippetInfo allocateArrayDynamic = snippet(NewObjectSnippets.class, "allocateArrayDynamic", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
 796                         TLAB_END_LOCATION);
 797         private final SnippetInfo allocateInstanceDynamic = snippet(NewObjectSnippets.class, "allocateInstanceDynamic", MARK_WORD_LOCATION, HUB_WRITE_LOCATION, TLAB_TOP_LOCATION,
 798                         TLAB_END_LOCATION, PROTOTYPE_MARK_WORD_LOCATION, CLASS_STATE_LOCATION);
 799         private final SnippetInfo newmultiarray = snippet(NewObjectSnippets.class, "newmultiarray", TLAB_TOP_LOCATION, TLAB_END_LOCATION);
 800         private final SnippetInfo newmultiarrayPIC = snippet(NewObjectSnippets.class, "newmultiarrayPIC", TLAB_TOP_LOCATION, TLAB_END_LOCATION);
 801         private final SnippetInfo verifyHeap = snippet(NewObjectSnippets.class, "verifyHeap");
 802         private final GraalHotSpotVMConfig config;
 803         private final Counters counters;
 804 
 805         public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, HotSpotProviders providers, TargetDescription target,
 806                         GraalHotSpotVMConfig config) {
 807             super(options, factories, providers, providers.getSnippetReflection(), target);
 808             this.config = config;
 809             counters = new Counters(factory);
 810         }
 811 
 812         /**
 813          * Lowers a {@link NewInstanceNode}.
 814          */
 815         public void lower(NewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 816             StructuredGraph graph = newInstanceNode.graph();
 817             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newInstanceNode.instanceClass();
 818             assert !type.isArray();
 819             ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
 820             long size = instanceSize(type);
 821 
 822             OptionValues localOptions = graph.getOptions();
 823             SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? allocateInstancePIC : allocateInstance;
 824             Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 825             args.addConst("size", size);
 826             args.add("hub", hub);
 827             args.add("prototypeMarkWord", type.prototypeMarkWord());
 828             args.addConst("fillContents", newInstanceNode.fillContents());
 829             args.addConst("emitMemoryBarrier", newInstanceNode.emitMemoryBarrier());
 830             args.addConst("threadRegister", registers.getThreadRegister());
 831             args.addConst("constantSize", true);
 832             args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? type.toJavaName(false) : "");
 833             args.addConst("counters", counters);
 834 
 835             SnippetTemplate template = template(newInstanceNode, args);
 836             graph.getDebug().log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
 837             template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
 838         }
 839 
 840         /**
 841          * Lowers a {@link NewArrayNode}.
 842          */
 843         public void lower(NewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 844             StructuredGraph graph = newArrayNode.graph();
 845             ResolvedJavaType elementType = newArrayNode.elementType();
 846             HotSpotResolvedObjectType arrayType = (HotSpotResolvedObjectType) elementType.getArrayClass();
 847             JavaKind elementKind = elementType.getJavaKind();
 848             ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayType.klass(), providers.getMetaAccess(), graph);
 849             final int headerSize = tool.getMetaAccess().getArrayBaseOffset(elementKind);
 850             int log2ElementSize = CodeUtil.log2(tool.getMetaAccess().getArrayIndexScale(elementKind));
 851 
 852             OptionValues localOptions = graph.getOptions();
 853             SnippetInfo snippet;
 854             if (GeneratePIC.getValue(localOptions)) {
 855                 if (elementType.isPrimitive()) {
 856                     snippet = allocatePrimitiveArrayPIC;
 857                 } else {
 858                     snippet = allocateArrayPIC;
 859                 }
 860             } else {
 861                 snippet = allocateArray;
 862             }
 863 
 864             Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 865             args.add("hub", hub);
 866             ValueNode length = newArrayNode.length();
 867             args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
 868             assert arrayType.prototypeMarkWord() == lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord() : "all array types are assumed to have the same prototypeMarkWord";
 869             args.add("prototypeMarkWord", arrayType.prototypeMarkWord());
 870             args.addConst("headerSize", headerSize);
 871             args.addConst("log2ElementSize", log2ElementSize);
 872             args.addConst("fillContents", newArrayNode.fillContents());
 873             args.addConst("emitMemoryBarrier", newArrayNode.emitMemoryBarrier());
 874             args.addConst("threadRegister", registers.getThreadRegister());
 875             args.addConst("maybeUnroll", length.isConstant());
 876             args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
 877             args.addConst("useBulkZeroing", tool.getLowerer().supportBulkZeroing());
 878             args.addConst("counters", counters);
 879             SnippetTemplate template = template(newArrayNode, args);
 880             graph.getDebug().log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
 881             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
 882         }
 883 
 884         public void lower(DynamicNewInstanceNode newInstanceNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 885             Arguments args = new Arguments(allocateInstanceDynamic, newInstanceNode.graph().getGuardsStage(), tool.getLoweringStage());
 886             args.add("type", newInstanceNode.getInstanceType());
 887             ValueNode classClass = newInstanceNode.getClassClass();
 888             assert classClass != null;
 889             args.add("classClass", classClass);
 890             args.addConst("fillContents", newInstanceNode.fillContents());
 891             args.addConst("emitMemoryBarrier", newInstanceNode.emitMemoryBarrier());
 892             args.addConst("threadRegister", registers.getThreadRegister());
 893             args.addConst("counters", counters);
 894 
 895             SnippetTemplate template = template(newInstanceNode, args);
 896             template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
 897         }
 898 
 899         public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 900             StructuredGraph graph = newArrayNode.graph();
 901             Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage());
 902             args.add("elementType", newArrayNode.getElementType());
 903             ValueNode voidClass = newArrayNode.getVoidClass();
 904             assert voidClass != null;
 905             args.add("voidClass", voidClass);
 906             ValueNode length = newArrayNode.length();
 907             args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
 908             args.addConst("fillContents", newArrayNode.fillContents());
 909             args.addConst("emitMemoryBarrier", newArrayNode.emitMemoryBarrier());
 910             args.addConst("threadRegister", registers.getThreadRegister());
 911             /*
 912              * We use Kind.Illegal as a marker value instead of null because constant snippet
 913              * parameters cannot be null.
 914              */
 915             args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? JavaKind.Illegal : newArrayNode.getKnownElementKind());
 916             if (newArrayNode.getKnownElementKind() != null) {
 917                 args.addConst("knownLayoutHelper", lookupArrayClass(tool, newArrayNode.getKnownElementKind()).layoutHelper());
 918             } else {
 919                 args.addConst("knownLayoutHelper", 0);
 920             }
 921             args.addConst("useBulkZeroing", tool.getLowerer().supportBulkZeroing());
 922             args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
 923             args.addConst("counters", counters);
 924             SnippetTemplate template = template(newArrayNode, args);
 925             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
 926         }
 927 
 928         private static HotSpotResolvedObjectType lookupArrayClass(LoweringTool tool, JavaKind kind) {
 929             return (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(kind == JavaKind.Object ? Object.class : kind.toJavaClass()).getArrayClass();
 930         }
 931 
 932         public void lower(NewMultiArrayNode newmultiarrayNode, LoweringTool tool) {
 933             StructuredGraph graph = newmultiarrayNode.graph();
 934             OptionValues localOptions = graph.getOptions();
 935             int rank = newmultiarrayNode.dimensionCount();
 936             ValueNode[] dims = new ValueNode[rank];
 937             for (int i = 0; i < newmultiarrayNode.dimensionCount(); i++) {
 938                 dims[i] = newmultiarrayNode.dimension(i);
 939             }
 940             HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) newmultiarrayNode.type();
 941             ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), graph);
 942 
 943             SnippetInfo snippet = GeneratePIC.getValue(localOptions) ? newmultiarrayPIC : newmultiarray;
 944             Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 945             args.add("hub", hub);
 946             args.addConst("rank", rank);
 947             args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims);
 948             template(newmultiarrayNode, args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
 949         }
 950 
 951         private static long instanceSize(HotSpotResolvedObjectType type) {
 952             long size = type.instanceSize();
 953             assert size >= 0;
 954             return size;
 955         }
 956 
 957         public void lower(VerifyHeapNode verifyHeapNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 958             if (config.cAssertions) {
 959                 Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
 960                 args.addConst("threadRegister", registers.getThreadRegister());
 961 
 962                 SnippetTemplate template = template(verifyHeapNode, args);
 963                 template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
 964             } else {
 965                 GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);
 966             }
 967         }
 968     }
 969 }