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