1 /* |
1 /* |
2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
25 package org.graalvm.compiler.nodes.extended; |
25 package org.graalvm.compiler.nodes.extended; |
26 |
26 |
27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; |
27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; |
28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; |
28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; |
29 |
29 |
|
30 import java.nio.ByteOrder; |
|
31 |
30 import org.graalvm.compiler.core.common.type.Stamp; |
32 import org.graalvm.compiler.core.common.type.Stamp; |
31 import org.graalvm.compiler.graph.Node; |
33 import org.graalvm.compiler.graph.Node; |
32 import org.graalvm.compiler.graph.NodeClass; |
34 import org.graalvm.compiler.graph.NodeClass; |
33 import org.graalvm.compiler.graph.spi.Canonicalizable; |
35 import org.graalvm.compiler.graph.spi.Canonicalizable; |
34 import org.graalvm.compiler.graph.spi.CanonicalizerTool; |
36 import org.graalvm.compiler.graph.spi.CanonicalizerTool; |
38 import org.graalvm.compiler.nodes.ValueNode; |
40 import org.graalvm.compiler.nodes.ValueNode; |
39 import org.graalvm.compiler.nodes.type.StampTool; |
41 import org.graalvm.compiler.nodes.type.StampTool; |
40 import jdk.internal.vm.compiler.word.LocationIdentity; |
42 import jdk.internal.vm.compiler.word.LocationIdentity; |
41 |
43 |
42 import jdk.vm.ci.meta.Assumptions; |
44 import jdk.vm.ci.meta.Assumptions; |
|
45 import jdk.vm.ci.meta.ConstantReflectionProvider; |
|
46 import jdk.vm.ci.meta.JavaConstant; |
43 import jdk.vm.ci.meta.JavaKind; |
47 import jdk.vm.ci.meta.JavaKind; |
44 import jdk.vm.ci.meta.ResolvedJavaField; |
48 import jdk.vm.ci.meta.ResolvedJavaField; |
45 import jdk.vm.ci.meta.ResolvedJavaType; |
49 import jdk.vm.ci.meta.ResolvedJavaType; |
46 |
50 |
47 @NodeInfo(cycles = CYCLES_2, size = SIZE_1) |
51 @NodeInfo(cycles = CYCLES_2, size = SIZE_1) |
93 long constantOffset = offset().asJavaConstant().asLong(); |
97 long constantOffset = offset().asJavaConstant().asLong(); |
94 |
98 |
95 // Try to canonicalize to a field access. |
99 // Try to canonicalize to a field access. |
96 ResolvedJavaType receiverType = StampTool.typeOrNull(object()); |
100 ResolvedJavaType receiverType = StampTool.typeOrNull(object()); |
97 if (receiverType != null) { |
101 if (receiverType != null) { |
98 ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind()); |
102 ResolvedJavaField field = getStaticFieldUnsafeAccess(tool.getConstantReflection()); |
99 // No need for checking that the receiver is non-null. The field access includes |
103 if (field == null) { |
100 // the null check and if a field is found, the offset is so small that this is |
104 field = receiverType.findInstanceFieldWithOffset(constantOffset, accessKind()); |
101 // never a valid access of an arbitrary address. |
105 } |
|
106 |
|
107 // No need for checking that the receiver is non-null. The field access |
|
108 // includes the null check and if a field is found, the offset is so small that |
|
109 // this is never a valid access of an arbitrary address. |
102 if (field != null && field.getJavaKind() == this.accessKind()) { |
110 if (field != null && field.getJavaKind() == this.accessKind()) { |
103 assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase"; |
111 assert !graph().isAfterFloatingReadPhase() : "cannot add more precise memory location after floating read phase"; |
104 // Unsafe accesses never have volatile semantics. |
112 // Unsafe accesses never have volatile semantics. |
105 // Memory barriers are placed around such an unsafe access at construction |
113 // Memory barriers are placed around such an unsafe access at construction |
106 // time if necessary, unlike AccessFieldNodes which encapsulate their |
114 // time if necessary, unlike AccessFieldNodes which encapsulate their |
126 } |
134 } |
127 |
135 |
128 protected abstract ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess); |
136 protected abstract ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess); |
129 |
137 |
130 protected abstract ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity); |
138 protected abstract ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity); |
|
139 |
|
140 /** |
|
141 * In this method we check if the unsafe access is to a static field. This is the case when |
|
142 * {@code object} is a constant of type {@link Class} (static field's declaring class) and |
|
143 * {@code offset} is a constant (HotSpot-specific field offset from the declaring class). |
|
144 * |
|
145 * @return the static field, if any, that this node is reading |
|
146 */ |
|
147 private ResolvedJavaField getStaticFieldUnsafeAccess(ConstantReflectionProvider constantReflection) { |
|
148 if (!object().isJavaConstant() || !offset().isJavaConstant() || |
|
149 object().isNullConstant() || offset().isNullConstant()) { |
|
150 return null; |
|
151 } |
|
152 JavaConstant objectConstant = object().asJavaConstant(); |
|
153 JavaConstant offsetConstant = offset().asJavaConstant(); |
|
154 assert objectConstant != null && offsetConstant != null : "Verified by the check at the beginning."; |
|
155 ResolvedJavaType staticReceiverType = constantReflection.asJavaType(objectConstant); |
|
156 if (staticReceiverType == null) { |
|
157 // object is not of type Class so it is not a static field |
|
158 return null; |
|
159 } |
|
160 return findStaticFieldWithOffset(staticReceiverType, offsetConstant.asLong(), accessKind); |
|
161 } |
|
162 |
|
163 private static ResolvedJavaField findStaticFieldWithOffset(ResolvedJavaType type, long offset, JavaKind expectedEntryKind) { |
|
164 try { |
|
165 ResolvedJavaField[] declaredFields = type.getStaticFields(); |
|
166 return findFieldWithOffset(offset, expectedEntryKind, declaredFields); |
|
167 } catch (UnsupportedOperationException e) { |
|
168 return null; |
|
169 } |
|
170 } |
|
171 |
|
172 /** |
|
173 * NOTE GR-18873: this is a copy-paste implementation derived from |
|
174 * {@code jdk.vm.ci.hotspot.HotSpotResolvedObjectTypeImpl#findStaticFieldWithOffset}. |
|
175 */ |
|
176 private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) { |
|
177 for (ResolvedJavaField field : declaredFields) { |
|
178 long resolvedFieldOffset = field.getOffset(); |
|
179 if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && |
|
180 expectedEntryKind.isPrimitive() && |
|
181 !expectedEntryKind.equals(JavaKind.Void) && |
|
182 field.getJavaKind().isPrimitive()) { |
|
183 resolvedFieldOffset += field.getJavaKind().getByteCount() - |
|
184 Math.min(field.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); |
|
185 } |
|
186 if (resolvedFieldOffset == offset) { |
|
187 return field; |
|
188 } |
|
189 } |
|
190 return null; |
|
191 } |
|
192 |
131 } |
193 } |