src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
changeset 58877 aec7bf35d6f5
parent 52910 583fd71c47d6
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Thu Oct 31 14:23:06 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java	Thu Oct 31 16:54:16 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
+import java.nio.ByteOrder;
+
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -40,6 +42,8 @@
 import jdk.internal.vm.compiler.word.LocationIdentity;
 
 import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaType;
@@ -95,10 +99,14 @@
                 // Try to canonicalize to a field access.
                 ResolvedJavaType receiverType = StampTool.typeOrNull(object());
                 if (receiverType != null) {
-                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind());
-                    // No need for checking that the receiver is non-null. The field access includes
-                    // the null check and if a field is found, the offset is so small that this is
-                    // never a valid access of an arbitrary address.
+                    ResolvedJavaField field = getStaticFieldUnsafeAccess(tool.getConstantReflection());
+                    if (field == null) {
+                        field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind());
+                    }
+
+                    // No need for checking that the receiver is non-null. The field access
+                    // includes the null check and if a field is found, the offset is so small that
+                    // this is never a valid access of an arbitrary address.
                     if (field != null && field.getJavaKind() == this.accessKind()) {
                         assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase";
                         // Unsafe accesses never have volatile semantics.
@@ -128,4 +136,58 @@
     protected abstract ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess);
 
     protected abstract ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity);
+
+    /**
+     * In this method we check if the unsafe access is to a static field. This is the case when
+     * {@code object} is a constant of type {@link Class} (static field's declaring class) and
+     * {@code offset} is a constant (HotSpot-specific field offset from the declaring class).
+     *
+     * @return the static field, if any, that this node is reading
+     */
+    private ResolvedJavaField getStaticFieldUnsafeAccess(ConstantReflectionProvider constantReflection) {
+        if (!object().isJavaConstant() || !offset().isJavaConstant() ||
+                        object().isNullConstant() || offset().isNullConstant()) {
+            return null;
+        }
+        JavaConstant objectConstant = object().asJavaConstant();
+        JavaConstant offsetConstant = offset().asJavaConstant();
+        assert objectConstant != null && offsetConstant != null : "Verified by the check at the beginning.";
+        ResolvedJavaType staticReceiverType = constantReflection.asJavaType(objectConstant);
+        if (staticReceiverType == null) {
+            // object is not of type Class so it is not a static field
+            return null;
+        }
+        return findStaticFieldWithOffset(staticReceiverType, offsetConstant.asLong(), accessKind);
+    }
+
+    private static ResolvedJavaField findStaticFieldWithOffset(ResolvedJavaType type, long offset, JavaKind expectedEntryKind) {
+        try {
+            ResolvedJavaField[] declaredFields = type.getStaticFields();
+            return findFieldWithOffset(offset, expectedEntryKind, declaredFields);
+        } catch (UnsupportedOperationException e) {
+            return null;
+        }
+    }
+
+    /**
+     * NOTE GR-18873: this is a copy-paste implementation derived from
+     * {@code jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl#findStaticFieldWithOffset}.
+     */
+    private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) {
+        for (ResolvedJavaField field : declaredFields) {
+            long resolvedFieldOffset = field.getOffset();
+            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN &&
+                            expectedEntryKind.isPrimitive() &&
+                            !expectedEntryKind.equals(JavaKind.Void) &&
+                            field.getJavaKind().isPrimitive()) {
+                resolvedFieldOffset += field.getJavaKind().getByteCount() -
+                                Math.min(field.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount());
+            }
+            if (resolvedFieldOffset == offset) {
+                return field;
+            }
+        }
+        return null;
+    }
+
 }