src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeAccessNode.java
--- 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;
+ }
+
}