1 /*
   2  * Copyright (c) 2012, 2018, 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 org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_METAACCESS;
  28 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
  29 import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.VERIFY_OOP;
  30 import static org.graalvm.compiler.hotspot.replacements.UnsafeAccess.UNSAFE;
  31 
  32 import org.graalvm.compiler.api.replacements.Fold;
  33 import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
  34 import org.graalvm.compiler.core.common.SuppressFBWarnings;
  35 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  36 import org.graalvm.compiler.core.common.type.ObjectStamp;
  37 import org.graalvm.compiler.core.common.type.TypeReference;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  40 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  41 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  42 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  43 import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
  44 import org.graalvm.compiler.hotspot.word.KlassPointer;
  45 import org.graalvm.compiler.nodes.CanonicalizableLocation;
  46 import org.graalvm.compiler.nodes.CompressionNode;
  47 import org.graalvm.compiler.nodes.ConstantNode;
  48 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  49 import org.graalvm.compiler.nodes.NodeView;
  50 import org.graalvm.compiler.nodes.ValueNode;
  51 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  52 import org.graalvm.compiler.nodes.extended.LoadHubNode;
  53 import org.graalvm.compiler.nodes.extended.RawLoadNode;
  54 import org.graalvm.compiler.nodes.extended.StoreHubNode;
  55 import org.graalvm.compiler.nodes.memory.Access;
  56 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  57 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  58 import org.graalvm.compiler.nodes.type.StampTool;
  59 import org.graalvm.compiler.replacements.ReplacementsUtil;
  60 import org.graalvm.compiler.replacements.nodes.ReadRegisterNode;
  61 import org.graalvm.compiler.replacements.nodes.WriteRegisterNode;
  62 import org.graalvm.compiler.word.Word;
  63 import jdk.internal.vm.compiler.word.LocationIdentity;
  64 import jdk.internal.vm.compiler.word.WordFactory;
  65 
  66 import jdk.vm.ci.code.Register;
  67 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  68 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
  69 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
  70 import jdk.vm.ci.meta.Assumptions;
  71 import jdk.vm.ci.meta.Assumptions.AssumptionResult;
  72 import jdk.vm.ci.meta.JavaKind;
  73 import jdk.vm.ci.meta.ResolvedJavaType;
  74 
  75 //JaCoCo Exclude
  76 
  77 /**
  78  * A collection of methods used in HotSpot snippets, substitutions and stubs.
  79  */
  80 public class HotSpotReplacementsUtil {
  81 
  82     abstract static class HotSpotOptimizingLocationIdentity extends NamedLocationIdentity implements CanonicalizableLocation {
  83 
  84         HotSpotOptimizingLocationIdentity(String name) {
  85             super(name, true);
  86         }
  87 
  88         @Override
  89         public abstract ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool);
  90 
  91         protected ValueNode findReadHub(ValueNode object) {
  92             ValueNode base = object;
  93             if (base instanceof CompressionNode) {
  94                 base = ((CompressionNode) base).getValue();
  95             }
  96             if (base instanceof Access) {
  97                 Access access = (Access) base;
  98                 if (access.getLocationIdentity().equals(HUB_LOCATION) || access.getLocationIdentity().equals(COMPRESSED_HUB_LOCATION)) {
  99                     AddressNode address = access.getAddress();
 100                     if (address instanceof OffsetAddressNode) {
 101                         OffsetAddressNode offset = (OffsetAddressNode) address;
 102                         return offset.getBase();
 103                     }
 104                 }
 105             } else if (base instanceof LoadHubNode) {
 106                 LoadHubNode loadhub = (LoadHubNode) base;
 107                 return loadhub.getValue();
 108             }
 109             return null;
 110         }
 111 
 112         /**
 113          * Fold reads that convert from Class -> Hub -> Class or vice versa.
 114          *
 115          * @param read
 116          * @param object
 117          * @param otherLocation
 118          * @return an earlier read or the original {@code read}
 119          */
 120         protected static ValueNode foldIndirection(ValueNode read, ValueNode object, LocationIdentity otherLocation) {
 121             if (object instanceof Access) {
 122                 Access access = (Access) object;
 123                 if (access.getLocationIdentity().equals(otherLocation)) {
 124                     AddressNode address = access.getAddress();
 125                     if (address instanceof OffsetAddressNode) {
 126                         OffsetAddressNode offset = (OffsetAddressNode) address;
 127                         assert offset.getBase().stamp(NodeView.DEFAULT).isCompatible(read.stamp(NodeView.DEFAULT));
 128                         return offset.getBase();
 129                     }
 130                 }
 131             }
 132             return read;
 133         }
 134     }
 135 
 136     public static HotSpotJVMCIRuntime runtime() {
 137         return HotSpotJVMCIRuntime.runtime();
 138     }
 139 
 140     @Fold
 141     public static int getHeapWordSize(@InjectedParameter GraalHotSpotVMConfig injectedVMConfig) {
 142         return injectedVMConfig.heapWordSize;
 143     }
 144 
 145     @Fold
 146     public static GraalHotSpotVMConfig config(@InjectedParameter GraalHotSpotVMConfig config) {
 147         assert config != null;
 148         return config;
 149     }
 150 
 151     @Fold
 152     public static boolean useTLAB(@InjectedParameter GraalHotSpotVMConfig config) {
 153         return config.useTLAB;
 154     }
 155 
 156     @Fold
 157     public static boolean verifyOops(@InjectedParameter GraalHotSpotVMConfig config) {
 158         return config.verifyOops;
 159     }
 160 
 161     public static final LocationIdentity EXCEPTION_OOP_LOCATION = NamedLocationIdentity.mutable("ExceptionOop");
 162 
 163     /**
 164      * @see GraalHotSpotVMConfig#threadExceptionOopOffset
 165      */
 166     @Fold
 167     public static int threadExceptionOopOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 168         return config.threadExceptionOopOffset;
 169     }
 170 
 171     public static final LocationIdentity EXCEPTION_PC_LOCATION = NamedLocationIdentity.mutable("ExceptionPc");
 172 
 173     @Fold
 174     public static int threadExceptionPcOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 175         return config.threadExceptionPcOffset;
 176     }
 177 
 178     public static final LocationIdentity TLAB_TOP_LOCATION = NamedLocationIdentity.mutable("TlabTop");
 179 
 180     @Fold
 181     public static int threadTlabTopOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 182         return config.threadTlabTopOffset();
 183     }
 184 
 185     public static final LocationIdentity TLAB_END_LOCATION = NamedLocationIdentity.mutable("TlabEnd");
 186 
 187     @Fold
 188     static int threadTlabEndOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 189         return config.threadTlabEndOffset();
 190     }
 191 
 192     public static final LocationIdentity PENDING_EXCEPTION_LOCATION = NamedLocationIdentity.mutable("PendingException");
 193 
 194     /**
 195      * @see GraalHotSpotVMConfig#pendingExceptionOffset
 196      */
 197     @Fold
 198     static int threadPendingExceptionOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 199         return config.pendingExceptionOffset;
 200     }
 201 
 202     public static final LocationIdentity OBJECT_RESULT_LOCATION = NamedLocationIdentity.mutable("ObjectResult");
 203 
 204     @Fold
 205     static int objectResultOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 206         return config.threadObjectResultOffset;
 207     }
 208 
 209     /**
 210      * @see GraalHotSpotVMConfig#threadExceptionOopOffset
 211      */
 212     public static Object readExceptionOop(Word thread) {
 213         return thread.readObject(threadExceptionOopOffset(INJECTED_VMCONFIG), EXCEPTION_OOP_LOCATION);
 214     }
 215 
 216     public static Word readExceptionPc(Word thread) {
 217         return thread.readWord(threadExceptionPcOffset(INJECTED_VMCONFIG), EXCEPTION_PC_LOCATION);
 218     }
 219 
 220     /**
 221      * @see GraalHotSpotVMConfig#threadExceptionOopOffset
 222      */
 223     public static void writeExceptionOop(Word thread, Object value) {
 224         thread.writeObject(threadExceptionOopOffset(INJECTED_VMCONFIG), value, EXCEPTION_OOP_LOCATION);
 225     }
 226 
 227     public static void writeExceptionPc(Word thread, Word value) {
 228         thread.writeWord(threadExceptionPcOffset(INJECTED_VMCONFIG), value, EXCEPTION_PC_LOCATION);
 229     }
 230 
 231     public static Word readTlabTop(Word thread) {
 232         return thread.readWord(threadTlabTopOffset(INJECTED_VMCONFIG), TLAB_TOP_LOCATION);
 233     }
 234 
 235     public static Word readTlabEnd(Word thread) {
 236         return thread.readWord(threadTlabEndOffset(INJECTED_VMCONFIG), TLAB_END_LOCATION);
 237     }
 238 
 239     public static void writeTlabTop(Word thread, Word top) {
 240         thread.writeWord(threadTlabTopOffset(INJECTED_VMCONFIG), top, TLAB_TOP_LOCATION);
 241     }
 242 
 243     /**
 244      * Clears the pending exception for the given thread.
 245      *
 246      * @return the pending exception, or null if there was none
 247      */
 248     @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
 249     public static Object clearPendingException(Word thread) {
 250         Object result = thread.readObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), PENDING_EXCEPTION_LOCATION);
 251         thread.writeObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), null, PENDING_EXCEPTION_LOCATION);
 252         return result;
 253     }
 254 
 255     /**
 256      * Gets the pending exception for the given thread.
 257      *
 258      * @return the pending exception, or null if there was none
 259      */
 260     @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF_NONVIRTUAL", justification = "foldable method parameters are injected")
 261     public static Object getPendingException(Word thread) {
 262         return thread.readObject(threadPendingExceptionOffset(INJECTED_VMCONFIG), PENDING_EXCEPTION_LOCATION);
 263     }
 264 
 265     /**
 266      * Gets and clears the object result from a runtime call stored in a thread local.
 267      *
 268      * @return the object that was in the thread local
 269      */
 270     public static Object getAndClearObjectResult(Word thread) {
 271         Object result = thread.readObject(objectResultOffset(INJECTED_VMCONFIG), OBJECT_RESULT_LOCATION);
 272         thread.writeObject(objectResultOffset(INJECTED_VMCONFIG), null, OBJECT_RESULT_LOCATION);
 273         return result;
 274     }
 275 
 276     /*
 277      * As far as Java code is concerned this can be considered immutable: it is set just after the
 278      * JavaThread is created, before it is published. After that, it is never changed.
 279      */
 280     public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj");
 281 
 282     @Fold
 283     public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 284         return config.threadObjectOffset;
 285     }
 286 
 287     public static final LocationIdentity JAVA_THREAD_OSTHREAD_LOCATION = NamedLocationIdentity.mutable("JavaThread::_osthread");
 288 
 289     @Fold
 290     public static int osThreadOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 291         return config.osThreadOffset;
 292     }
 293 
 294     @Fold
 295     public static int osThreadInterruptedOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 296         return config.osThreadInterruptedOffset;
 297     }
 298 
 299     @Fold
 300     public static JavaKind getWordKind() {
 301         return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordJavaKind;
 302     }
 303 
 304     @Fold
 305     public static int wordSize() {
 306         return runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize;
 307     }
 308 
 309     @Fold
 310     public static int pageSize() {
 311         return UNSAFE.pageSize();
 312     }
 313 
 314     public static final LocationIdentity PROTOTYPE_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("PrototypeMarkWord");
 315 
 316     @Fold
 317     public static int prototypeMarkWordOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 318         return config.prototypeMarkWordOffset;
 319     }
 320 
 321     public static final LocationIdentity KLASS_ACCESS_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_access_flags");
 322 
 323     @Fold
 324     public static int klassAccessFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 325         return config.klassAccessFlagsOffset;
 326     }
 327 
 328     @Fold
 329     public static int jvmAccWrittenFlags(@InjectedParameter GraalHotSpotVMConfig config) {
 330         return config.jvmAccWrittenFlags;
 331     }
 332 
 333     public static final LocationIdentity KLASS_LAYOUT_HELPER_LOCATION = new HotSpotOptimizingLocationIdentity("Klass::_layout_helper") {
 334         @Override
 335         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 336             ValueNode javaObject = findReadHub(object);
 337             if (javaObject != null) {
 338                 if (javaObject.stamp(NodeView.DEFAULT) instanceof ObjectStamp) {
 339                     ObjectStamp stamp = (ObjectStamp) javaObject.stamp(NodeView.DEFAULT);
 340                     HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) stamp.javaType(tool.getMetaAccess());
 341                     if (type.isArray() && !type.getComponentType().isPrimitive()) {
 342                         int layout = type.layoutHelper();
 343                         return ConstantNode.forInt(layout);
 344                     }
 345                 }
 346             }
 347             return read;
 348         }
 349     };
 350 
 351     @NodeIntrinsic(value = KlassLayoutHelperNode.class)
 352     public static native int readLayoutHelper(KlassPointer object);
 353 
 354     /**
 355      * Checks if class {@code klass} is an array.
 356      *
 357      * See: Klass::layout_helper_is_array
 358      *
 359      * @param klassNonNull the class to be checked
 360      * @return true if klassNonNull is an array, false otherwise
 361      */
 362     public static boolean klassIsArray(KlassPointer klassNonNull) {
 363         /*
 364          * The less-than check only works if both values are ints. We use local variables to make
 365          * sure these are still ints and haven't changed.
 366          */
 367         final int layoutHelper = readLayoutHelper(klassNonNull);
 368         final int layoutHelperNeutralValue = config(INJECTED_VMCONFIG).klassLayoutHelperNeutralValue;
 369         return (layoutHelper < layoutHelperNeutralValue);
 370     }
 371 
 372     public static final LocationIdentity ARRAY_KLASS_COMPONENT_MIRROR = NamedLocationIdentity.immutable("ArrayKlass::_component_mirror");
 373 
 374     @Fold
 375     public static int arrayKlassComponentMirrorOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 376         return config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop");
 377     }
 378 
 379     public static final LocationIdentity KLASS_SUPER_KLASS_LOCATION = NamedLocationIdentity.immutable("Klass::_super");
 380 
 381     @Fold
 382     public static int klassSuperKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 383         return config.klassSuperKlassOffset;
 384     }
 385 
 386     public static final LocationIdentity MARK_WORD_LOCATION = NamedLocationIdentity.mutable("MarkWord");
 387 
 388     @Fold
 389     public static int markOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 390         return config.markOffset;
 391     }
 392 
 393     public static final LocationIdentity HUB_WRITE_LOCATION = NamedLocationIdentity.mutable("Hub:write");
 394 
 395     public static final LocationIdentity HUB_LOCATION = new HotSpotOptimizingLocationIdentity("Hub") {
 396         @Override
 397         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 398             TypeReference constantType = StampTool.typeReferenceOrNull(object);
 399             if (constantType != null && constantType.isExact()) {
 400                 return ConstantNode.forConstant(read.stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(constantType.getType()), tool.getMetaAccess());
 401             }
 402             return read;
 403         }
 404     };
 405 
 406     public static final LocationIdentity COMPRESSED_HUB_LOCATION = new HotSpotOptimizingLocationIdentity("CompressedHub") {
 407         @Override
 408         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 409             TypeReference constantType = StampTool.typeReferenceOrNull(object);
 410             if (constantType != null && constantType.isExact()) {
 411                 return ConstantNode.forConstant(read.stamp(NodeView.DEFAULT), ((HotSpotMetaspaceConstant) tool.getConstantReflection().asObjectHub(constantType.getType())).compress(),
 412                                 tool.getMetaAccess());
 413             }
 414             return read;
 415         }
 416     };
 417 
 418     @Fold
 419     static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 420         return config.hubOffset;
 421     }
 422 
 423     public static void initializeObjectHeader(Word memory, Word markWord, KlassPointer hub) {
 424         memory.writeWord(markOffset(INJECTED_VMCONFIG), markWord, MARK_WORD_LOCATION);
 425         StoreHubNode.write(memory, hub);
 426     }
 427 
 428     @Fold
 429     public static int unlockedMask(@InjectedParameter GraalHotSpotVMConfig config) {
 430         return config.unlockedMask;
 431     }
 432 
 433     @Fold
 434     public static int monitorMask(@InjectedParameter GraalHotSpotVMConfig config) {
 435         return config.monitorMask;
 436     }
 437 
 438     @Fold
 439     public static int objectMonitorOwnerOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 440         return config.objectMonitorOwner;
 441     }
 442 
 443     @Fold
 444     public static int objectMonitorRecursionsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 445         return config.objectMonitorRecursions;
 446     }
 447 
 448     @Fold
 449     public static int objectMonitorCxqOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 450         return config.objectMonitorCxq;
 451     }
 452 
 453     @Fold
 454     public static int objectMonitorEntryListOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 455         return config.objectMonitorEntryList;
 456     }
 457 
 458     /**
 459      * Mask for a biasable, locked or unlocked mark word.
 460      *
 461      * <pre>
 462      * +----------------------------------+-+-+
 463      * |                                 1|1|1|
 464      * +----------------------------------+-+-+
 465      * </pre>
 466      *
 467      */
 468     @Fold
 469     public static int biasedLockMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
 470         return config.biasedLockMaskInPlace;
 471     }
 472 
 473     @Fold
 474     public static int epochMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
 475         return config.epochMaskInPlace;
 476     }
 477 
 478     /**
 479      * Pattern for a biasable, unlocked mark word.
 480      *
 481      * <pre>
 482      * +----------------------------------+-+-+
 483      * |                                 1|0|1|
 484      * +----------------------------------+-+-+
 485      * </pre>
 486      *
 487      */
 488     @Fold
 489     public static int biasedLockPattern(@InjectedParameter GraalHotSpotVMConfig config) {
 490         return config.biasedLockPattern;
 491     }
 492 
 493     @Fold
 494     public static int ageMaskInPlace(@InjectedParameter GraalHotSpotVMConfig config) {
 495         return config.ageMaskInPlace;
 496     }
 497 
 498     @Fold
 499     public static int metaspaceArrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 500         return config.metaspaceArrayLengthOffset;
 501     }
 502 
 503     @Fold
 504     public static int metaspaceArrayBaseOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 505         return config.metaspaceArrayBaseOffset;
 506     }
 507 
 508     @Fold
 509     public static int arrayLengthOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 510         return config.arrayOopDescLengthOffset();
 511     }
 512 
 513     public static Word arrayStart(int[] a) {
 514         return WordFactory.unsigned(ComputeObjectAddressNode.get(a, ReplacementsUtil.getArrayBaseOffset(INJECTED_METAACCESS, JavaKind.Int)));
 515     }
 516 
 517     /**
 518      * Idiom for making {@link GraalHotSpotVMConfig} a constant.
 519      */
 520     @Fold
 521     public static GraalHotSpotVMConfig getConfig(@InjectedParameter GraalHotSpotVMConfig config) {
 522         return config;
 523     }
 524 
 525     /**
 526      * Calls {@link #arrayAllocationSize(int, int, int, GraalHotSpotVMConfig)} using an injected VM
 527      * configuration object.
 528      */
 529     public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize) {
 530         return arrayAllocationSize(length, headerSize, log2ElementSize, getConfig(INJECTED_VMCONFIG));
 531     }
 532 
 533     /**
 534      * Computes the size of the memory chunk allocated for an array. This size accounts for the
 535      * array header size, body size and any padding after the last element to satisfy object
 536      * alignment requirements.
 537      *
 538      * @param length the number of elements in the array
 539      * @param headerSize the size of the array header
 540      * @param log2ElementSize log2 of the size of an element in the array
 541      * @param config the VM configuration providing the
 542      *            {@linkplain GraalHotSpotVMConfig#objectAlignment object alignment requirement}
 543      * @return the size of the memory chunk
 544      */
 545     public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize, GraalHotSpotVMConfig config) {
 546         int alignment = config.objectAlignment;
 547         int size = (length << log2ElementSize) + headerSize + (alignment - 1);
 548         int mask = ~(alignment - 1);
 549         return size & mask;
 550     }
 551 
 552     @Fold
 553     public static int instanceHeaderSize(@InjectedParameter GraalHotSpotVMConfig config) {
 554         return config.useCompressedClassPointers ? (2 * wordSize()) - 4 : 2 * wordSize();
 555     }
 556 
 557     @Fold
 558     public static byte dirtyCardValue(@InjectedParameter GraalHotSpotVMConfig config) {
 559         return config.dirtyCardValue;
 560     }
 561 
 562     @Fold
 563     public static byte g1YoungCardValue(@InjectedParameter GraalHotSpotVMConfig config) {
 564         return config.g1YoungCardValue;
 565     }
 566 
 567     @Fold
 568     public static int cardTableShift(@InjectedParameter GraalHotSpotVMConfig config) {
 569         return config.cardtableShift;
 570     }
 571 
 572     @Fold
 573     public static int g1CardQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 574         return config.g1CardQueueIndexOffset;
 575     }
 576 
 577     @Fold
 578     public static int g1CardQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 579         return config.g1CardQueueBufferOffset;
 580     }
 581 
 582     @Fold
 583     public static int g1SATBQueueMarkingOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 584         return config.g1SATBQueueMarkingOffset;
 585     }
 586 
 587     @Fold
 588     public static int g1SATBQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 589         return config.g1SATBQueueIndexOffset;
 590     }
 591 
 592     @Fold
 593     public static int g1SATBQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 594         return config.g1SATBQueueBufferOffset;
 595     }
 596 
 597     public static final LocationIdentity KLASS_SUPER_CHECK_OFFSET_LOCATION = NamedLocationIdentity.immutable("Klass::_super_check_offset");
 598 
 599     @Fold
 600     public static int superCheckOffsetOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 601         return config.superCheckOffsetOffset;
 602     }
 603 
 604     public static final LocationIdentity SECONDARY_SUPER_CACHE_LOCATION = NamedLocationIdentity.mutable("SecondarySuperCache");
 605 
 606     @Fold
 607     public static int secondarySuperCacheOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 608         return config.secondarySuperCacheOffset;
 609     }
 610 
 611     public static final LocationIdentity SECONDARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("SecondarySupers");
 612 
 613     @Fold
 614     public static int secondarySupersOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 615         return config.secondarySupersOffset;
 616     }
 617 
 618     public static final LocationIdentity DISPLACED_MARK_WORD_LOCATION = NamedLocationIdentity.mutable("DisplacedMarkWord");
 619 
 620     public static final LocationIdentity OBJECT_MONITOR_OWNER_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_owner");
 621 
 622     public static final LocationIdentity OBJECT_MONITOR_RECURSION_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_recursions");
 623 
 624     public static final LocationIdentity OBJECT_MONITOR_CXQ_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_cxq");
 625 
 626     public static final LocationIdentity OBJECT_MONITOR_ENTRY_LIST_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_EntryList");
 627 
 628     @Fold
 629     public static int lockDisplacedMarkOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 630         return config.basicLockDisplacedHeaderOffset;
 631     }
 632 
 633     @Fold
 634     public static boolean useBiasedLocking(@InjectedParameter GraalHotSpotVMConfig config) {
 635         return config.useBiasedLocking;
 636     }
 637 
 638     @Fold
 639     static int uninitializedIdentityHashCodeValue(@InjectedParameter GraalHotSpotVMConfig config) {
 640         return config.uninitializedIdentityHashCodeValue;
 641     }
 642 
 643     @Fold
 644     static int identityHashCodeShift(@InjectedParameter GraalHotSpotVMConfig config) {
 645         return config.identityHashCodeShift;
 646     }
 647 
 648     /**
 649      * Loads the hub of an object (without null checking it first).
 650      */
 651     public static KlassPointer loadHub(Object object) {
 652         return loadHubIntrinsic(object);
 653     }
 654 
 655     public static Object verifyOop(Object object) {
 656         if (verifyOops(INJECTED_VMCONFIG)) {
 657             verifyOopStub(VERIFY_OOP, object);
 658         }
 659         return object;
 660     }
 661 
 662     @NodeIntrinsic(ForeignCallNode.class)
 663     private static native Object verifyOopStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
 664 
 665     public static Word loadWordFromObject(Object object, int offset) {
 666         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
 667         return loadWordFromObjectIntrinsic(object, offset, LocationIdentity.any(), getWordKind());
 668     }
 669 
 670     public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) {
 671         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
 672         return loadWordFromObjectIntrinsic(object, offset, identity, getWordKind());
 673     }
 674 
 675     public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) {
 676         ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject");
 677         return loadKlassFromObjectIntrinsic(object, offset, identity, getWordKind());
 678     }
 679 
 680     /**
 681      * Reads the value of a given register.
 682      *
 683      * @param register a register which must not be available to the register allocator
 684      * @return the value of {@code register} as a word
 685      */
 686     public static Word registerAsWord(@ConstantNodeParameter Register register) {
 687         return registerAsWord(register, true, false);
 688     }
 689 
 690     @NodeIntrinsic(value = ReadRegisterNode.class)
 691     public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming);
 692 
 693     @NodeIntrinsic(value = WriteRegisterNode.class)
 694     public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value);
 695 
 696     @NodeIntrinsic(value = RawLoadNode.class)
 697     private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind);
 698 
 699     @NodeIntrinsic(value = RawLoadNode.class)
 700     private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind);
 701 
 702     @NodeIntrinsic(value = LoadHubNode.class)
 703     public static native KlassPointer loadHubIntrinsic(Object object);
 704 
 705     public static final LocationIdentity CLASS_STATE_LOCATION = NamedLocationIdentity.mutable("ClassState");
 706 
 707     @Fold
 708     public static int instanceKlassInitStateOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 709         return config.instanceKlassInitStateOffset;
 710     }
 711 
 712     @Fold
 713     public static int instanceKlassStateFullyInitialized(@InjectedParameter GraalHotSpotVMConfig config) {
 714         return config.instanceKlassStateFullyInitialized;
 715     }
 716 
 717     /**
 718      *
 719      * @param hub the hub of an InstanceKlass
 720      * @return true is the InstanceKlass represented by hub is fully initialized
 721      */
 722     public static boolean isInstanceKlassFullyInitialized(KlassPointer hub) {
 723         return readInstanceKlassState(hub) == instanceKlassStateFullyInitialized(INJECTED_VMCONFIG);
 724     }
 725 
 726     private static byte readInstanceKlassState(KlassPointer hub) {
 727         return hub.readByte(instanceKlassInitStateOffset(INJECTED_VMCONFIG), CLASS_STATE_LOCATION);
 728     }
 729 
 730     public static final LocationIdentity KLASS_MODIFIER_FLAGS_LOCATION = NamedLocationIdentity.immutable("Klass::_modifier_flags");
 731 
 732     @Fold
 733     public static int klassModifierFlagsOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 734         return config.klassModifierFlagsOffset;
 735     }
 736 
 737     public static final LocationIdentity CLASS_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._klass") {
 738         @Override
 739         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 740             return foldIndirection(read, object, CLASS_MIRROR_LOCATION);
 741         }
 742     };
 743 
 744     public static final LocationIdentity CLASS_ARRAY_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("Class._array_klass") {
 745         @Override
 746         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 747             return foldIndirection(read, object, ARRAY_KLASS_COMPONENT_MIRROR);
 748         }
 749     };
 750 
 751     @Fold
 752     public static int arrayKlassOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 753         return config.arrayKlassOffset;
 754     }
 755 
 756     public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror");
 757 
 758     public static final LocationIdentity CLASS_MIRROR_HANDLE_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror handle");
 759 
 760     @Fold
 761     public static int layoutHelperHeaderSizeShift(@InjectedParameter GraalHotSpotVMConfig config) {
 762         return config.layoutHelperHeaderSizeShift;
 763     }
 764 
 765     @Fold
 766     public static int layoutHelperHeaderSizeMask(@InjectedParameter GraalHotSpotVMConfig config) {
 767         return config.layoutHelperHeaderSizeMask;
 768     }
 769 
 770     @Fold
 771     public static int layoutHelperLog2ElementSizeShift(@InjectedParameter GraalHotSpotVMConfig config) {
 772         return config.layoutHelperLog2ElementSizeShift;
 773     }
 774 
 775     @Fold
 776     public static int layoutHelperLog2ElementSizeMask(@InjectedParameter GraalHotSpotVMConfig config) {
 777         return config.layoutHelperLog2ElementSizeMask;
 778     }
 779 
 780     @NodeIntrinsic(ForeignCallNode.class)
 781     public static native int identityHashCode(@ConstantNodeParameter ForeignCallDescriptor descriptor, Object object);
 782 
 783     @Fold
 784     public static long gcTotalCollectionsAddress(@InjectedParameter GraalHotSpotVMConfig config) {
 785         return config.gcTotalCollectionsAddress();
 786     }
 787 
 788     @Fold
 789     public static long referentOffset() {
 790         try {
 791             return UNSAFE.objectFieldOffset(java.lang.ref.Reference.class.getDeclaredField("referent"));
 792         } catch (Exception e) {
 793             throw new GraalError(e);
 794         }
 795     }
 796 
 797     public static final LocationIdentity OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION = new HotSpotOptimizingLocationIdentity("ObjArrayKlass::_element_klass") {
 798         @Override
 799         public ValueNode canonicalizeRead(ValueNode read, AddressNode location, ValueNode object, CanonicalizerTool tool) {
 800             ValueNode javaObject = findReadHub(object);
 801             if (javaObject != null) {
 802                 ResolvedJavaType type = StampTool.typeOrNull(javaObject);
 803                 if (type != null && type.isArray()) {
 804                     ResolvedJavaType element = type.getComponentType();
 805                     if (element != null && !element.isPrimitive() && !element.getElementalType().isInterface()) {
 806                         Assumptions assumptions = object.graph().getAssumptions();
 807                         AssumptionResult<ResolvedJavaType> leafType = element.findLeafConcreteSubtype();
 808                         if (leafType != null && leafType.canRecordTo(assumptions)) {
 809                             leafType.recordTo(assumptions);
 810                             return ConstantNode.forConstant(read.stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(leafType.getResult()), tool.getMetaAccess());
 811                         }
 812                     }
 813                 }
 814             }
 815             return read;
 816         }
 817     };
 818 
 819     @Fold
 820     public static int arrayClassElementOffset(@InjectedParameter GraalHotSpotVMConfig config) {
 821         return config.arrayClassElementOffset;
 822     }
 823 
 824     public static final LocationIdentity PRIMARY_SUPERS_LOCATION = NamedLocationIdentity.immutable("PrimarySupers");
 825 
 826     public static final LocationIdentity METASPACE_ARRAY_LENGTH_LOCATION = NamedLocationIdentity.immutable("MetaspaceArrayLength");
 827 
 828     public static final LocationIdentity SECONDARY_SUPERS_ELEMENT_LOCATION = NamedLocationIdentity.immutable("SecondarySupersElement");
 829 }