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}