20 * or visit www.oracle.com if you need additional information or have any |
20 * or visit www.oracle.com if you need additional information or have any |
21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 package jdk.vm.ci.hotspot; |
23 package jdk.vm.ci.hotspot; |
24 |
24 |
|
25 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; |
25 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; |
26 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; |
26 |
27 |
27 import java.lang.reflect.Array; |
|
28 |
|
29 import jdk.vm.ci.common.JVMCIError; |
|
30 import jdk.vm.ci.meta.Constant; |
28 import jdk.vm.ci.meta.Constant; |
31 import jdk.vm.ci.meta.JavaConstant; |
29 import jdk.vm.ci.meta.JavaConstant; |
32 import jdk.vm.ci.meta.JavaKind; |
30 import jdk.vm.ci.meta.JavaKind; |
33 import jdk.vm.ci.meta.MemoryAccessProvider; |
31 import jdk.vm.ci.meta.MemoryAccessProvider; |
34 import jdk.vm.ci.meta.MetaAccessProvider; |
|
35 import jdk.vm.ci.meta.PrimitiveConstant; |
32 import jdk.vm.ci.meta.PrimitiveConstant; |
36 import jdk.vm.ci.meta.ResolvedJavaField; |
|
37 import jdk.vm.ci.meta.ResolvedJavaType; |
|
38 |
33 |
39 /** |
34 /** |
40 * HotSpot implementation of {@link MemoryAccessProvider}. |
35 * HotSpot implementation of {@link MemoryAccessProvider}. |
41 */ |
36 */ |
42 class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { |
37 class HotSpotMemoryAccessProviderImpl implements HotSpotMemoryAccessProvider { |
53 * |
48 * |
54 * @param base constant value containing the base address for a pending read |
49 * @param base constant value containing the base address for a pending read |
55 * @return {@code null} if {@code base} does not box an object otherwise the object boxed in |
50 * @return {@code null} if {@code base} does not box an object otherwise the object boxed in |
56 * {@code base} |
51 * {@code base} |
57 */ |
52 */ |
58 private Object asObject(Constant base, JavaKind kind, long displacement) { |
53 private static HotSpotObjectConstantImpl asObject(Constant base, JavaKind kind, long displacement) { |
59 if (base instanceof HotSpotObjectConstantImpl) { |
54 if (base instanceof HotSpotObjectConstantImpl) { |
60 HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base; |
55 HotSpotObjectConstantImpl constant = (HotSpotObjectConstantImpl) base; |
61 HotSpotResolvedObjectType type = constant.getType(); |
56 HotSpotResolvedObjectType type = constant.getType(); |
62 Object object = constant.object(); |
57 runtime().reflection.checkRead(constant, kind, displacement, type); |
63 checkRead(kind, displacement, type, object, runtime.getHostJVMCIBackend().getMetaAccess()); |
58 return constant; |
64 return object; |
|
65 } |
59 } |
66 return null; |
60 return null; |
67 } |
61 } |
68 |
62 |
69 /** |
63 private boolean isValidObjectFieldDisplacement(Constant base, long displacement) { |
70 * Offset of injected {@code java.lang.Class::oop_size} field. No need to make {@code volatile} |
64 if (base instanceof HotSpotMetaspaceConstant) { |
71 * as initialization is idempotent. |
65 MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
72 */ |
66 if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { |
73 private long oopSizeOffset; |
67 if (displacement == runtime.getConfig().javaMirrorOffset) { |
74 |
68 // Klass::_java_mirror is valid for all Klass* values |
75 private static int computeOopSizeOffset(HotSpotJVMCIRuntime runtime) { |
69 return true; |
76 MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess(); |
|
77 ResolvedJavaType staticType = metaAccess.lookupJavaType(Class.class); |
|
78 for (ResolvedJavaField f : staticType.getInstanceFields(false)) { |
|
79 if (f.getName().equals("oop_size")) { |
|
80 int offset = ((HotSpotResolvedJavaField) f).getOffset(); |
|
81 assert offset != 0 : "not expecting offset of java.lang.Class::oop_size to be 0"; |
|
82 return offset; |
|
83 } |
|
84 } |
|
85 throw new JVMCIError("Could not find injected java.lang.Class::oop_size field"); |
|
86 } |
|
87 |
|
88 private boolean checkRead(JavaKind kind, long displacement, HotSpotResolvedObjectType type, Object object, MetaAccessProvider metaAccess) { |
|
89 if (type.isArray()) { |
|
90 ResolvedJavaType componentType = type.getComponentType(); |
|
91 JavaKind componentKind = componentType.getJavaKind(); |
|
92 final int headerSize = metaAccess.getArrayBaseOffset(componentKind); |
|
93 int sizeOfElement = metaAccess.getArrayIndexScale(componentKind); |
|
94 int length = Array.getLength(object); |
|
95 long arrayEnd = headerSize + (sizeOfElement * length); |
|
96 boolean aligned = ((displacement - headerSize) % sizeOfElement) == 0; |
|
97 if (displacement < 0 || displacement > (arrayEnd - sizeOfElement) || (kind == JavaKind.Object && !aligned)) { |
|
98 int index = (int) ((displacement - headerSize) / sizeOfElement); |
|
99 throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind + |
|
100 " at offset " + displacement + " (index ~ " + index + ") in " + |
|
101 type.toJavaName() + " object of length " + length); |
|
102 } |
|
103 } else if (kind != JavaKind.Object) { |
|
104 long size; |
|
105 if (object instanceof Class) { |
|
106 if (oopSizeOffset == 0) { |
|
107 oopSizeOffset = computeOopSizeOffset(runtime); |
|
108 } |
70 } |
109 int wordSize = runtime.getHostJVMCIBackend().getCodeCache().getTarget().wordSize; |
|
110 size = UNSAFE.getInt(object, oopSizeOffset) * wordSize; |
|
111 } else { |
71 } else { |
112 size = Math.abs(type.instanceSize()); |
72 throw new IllegalArgumentException(String.valueOf(metaspaceObject)); |
113 } |
73 } |
114 int bytesToRead = kind.getByteCount(); |
74 } |
115 if (displacement + bytesToRead > size || displacement < 0) { |
75 return false; |
116 throw new IllegalArgumentException("Unsafe access: reading " + bytesToRead + " bytes at offset " + displacement + " in " + |
|
117 type.toJavaName() + " object of size " + size); |
|
118 } |
|
119 } else { |
|
120 ResolvedJavaField field = type.findInstanceFieldWithOffset(displacement, JavaKind.Object); |
|
121 if (field == null && object instanceof Class) { |
|
122 // Read of a static field |
|
123 HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) metaAccess.lookupJavaType((Class<?>) object); |
|
124 field = staticFieldsHolder.findStaticFieldWithOffset(displacement, JavaKind.Object); |
|
125 } |
|
126 if (field == null) { |
|
127 throw new IllegalArgumentException("Unsafe object access: field not found for read of kind Object" + |
|
128 " at offset " + displacement + " in " + type.toJavaName() + " object"); |
|
129 } |
|
130 if (field.getJavaKind() != JavaKind.Object) { |
|
131 throw new IllegalArgumentException("Unsafe object access: field " + field.format("%H.%n:%T") + " not of expected kind Object" + |
|
132 " at offset " + displacement + " in " + type.toJavaName() + " object"); |
|
133 } |
|
134 } |
|
135 return true; |
|
136 } |
76 } |
137 |
77 |
138 private static long asRawPointer(Constant base) { |
78 private static long asRawPointer(Constant base) { |
139 if (base instanceof HotSpotMetaspaceConstantImpl) { |
79 if (base instanceof HotSpotMetaspaceConstantImpl) { |
140 MetaspaceWrapperObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
80 MetaspaceObject meta = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
141 return meta.getMetaspacePointer(); |
81 return meta.getMetaspacePointer(); |
142 } else if (base instanceof PrimitiveConstant) { |
82 } else if (base instanceof PrimitiveConstant) { |
143 PrimitiveConstant prim = (PrimitiveConstant) base; |
83 PrimitiveConstant prim = (PrimitiveConstant) base; |
144 if (prim.getJavaKind().isNumericInteger()) { |
84 if (prim.getJavaKind().isNumericInteger()) { |
145 return prim.asLong(); |
85 return prim.asLong(); |
146 } |
86 } |
147 } |
87 } |
148 throw new IllegalArgumentException(String.valueOf(base)); |
88 throw new IllegalArgumentException(String.valueOf(base)); |
149 } |
89 } |
150 |
90 |
151 private long readRawValue(Constant baseConstant, long displacement, JavaKind kind, int bits) { |
91 private static long readRawValue(Constant baseConstant, long displacement, JavaKind kind, int bits) { |
152 Object base = asObject(baseConstant, kind, displacement); |
92 HotSpotObjectConstantImpl base = asObject(baseConstant, kind, displacement); |
153 if (base != null) { |
93 if (base != null) { |
154 switch (bits) { |
94 switch (bits) { |
155 case Byte.SIZE: |
95 case Byte.SIZE: |
156 return UNSAFE.getByte(base, displacement); |
96 return runtime().reflection.getByte(base, displacement); |
157 case Short.SIZE: |
97 case Short.SIZE: |
158 return UNSAFE.getShort(base, displacement); |
98 return runtime().reflection.getShort(base, displacement); |
159 case Integer.SIZE: |
99 case Integer.SIZE: |
160 return UNSAFE.getInt(base, displacement); |
100 return runtime().reflection.getInt(base, displacement); |
161 case Long.SIZE: |
101 case Long.SIZE: |
162 return UNSAFE.getLong(base, displacement); |
102 return runtime().reflection.getLong(base, displacement); |
163 default: |
103 default: |
164 throw new IllegalArgumentException(String.valueOf(bits)); |
104 throw new IllegalArgumentException(String.valueOf(bits)); |
165 } |
105 } |
166 } else { |
106 } else { |
167 long pointer = asRawPointer(baseConstant); |
107 long pointer = asRawPointer(baseConstant); |
178 throw new IllegalArgumentException(String.valueOf(bits)); |
118 throw new IllegalArgumentException(String.valueOf(bits)); |
179 } |
119 } |
180 } |
120 } |
181 } |
121 } |
182 |
122 |
183 private boolean verifyReadRawObject(Object expected, Constant base, long displacement) { |
123 private boolean verifyReadRawObject(JavaConstant expected, Constant base, long displacement) { |
184 if (base instanceof HotSpotMetaspaceConstant) { |
124 if (base instanceof HotSpotMetaspaceConstant) { |
185 MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
125 MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
186 if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { |
126 if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { |
187 if (displacement == runtime.getConfig().classMirrorHandleOffset) { |
127 if (displacement == runtime.getConfig().javaMirrorOffset) { |
188 assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror(); |
128 HotSpotResolvedObjectTypeImpl type = (HotSpotResolvedObjectTypeImpl) metaspaceObject; |
|
129 assert expected.equals(type.getJavaMirror()); |
189 } |
130 } |
190 } |
131 } |
191 } |
132 } |
192 return true; |
133 return true; |
193 } |
134 } |
194 |
135 |
195 private Object readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { |
136 private JavaConstant readRawObject(Constant baseConstant, long initialDisplacement, boolean compressed) { |
196 long displacement = initialDisplacement; |
137 long displacement = initialDisplacement; |
197 Object ret; |
138 JavaConstant ret; |
198 Object base = asObject(baseConstant, JavaKind.Object, displacement); |
139 HotSpotObjectConstantImpl base = asObject(baseConstant, JavaKind.Object, displacement); |
199 if (base == null) { |
140 if (base == null) { |
200 assert !compressed; |
141 assert !compressed; |
201 displacement += asRawPointer(baseConstant); |
142 displacement += asRawPointer(baseConstant); |
202 ret = UNSAFE.getUncompressedObject(displacement); |
143 ret = runtime.getCompilerToVM().readUncompressedOop(displacement); |
203 assert verifyReadRawObject(ret, baseConstant, initialDisplacement); |
144 assert verifyReadRawObject(ret, baseConstant, initialDisplacement); |
204 } else { |
145 } else { |
205 assert runtime.getConfig().useCompressedOops == compressed; |
146 assert runtime.getConfig().useCompressedOops == compressed; |
206 ret = UNSAFE.getReference(base, displacement); |
147 ret = runtime.getCompilerToVM().getObject(base, displacement); |
207 } |
148 } |
208 return ret; |
149 return ret == null ? JavaConstant.NULL_POINTER : ret; |
209 } |
|
210 |
|
211 JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean isVolatile) { |
|
212 assert obj != null; |
|
213 assert !field.isStatic() || obj instanceof Class; |
|
214 long displacement = field.getOffset(); |
|
215 assert checkRead(field.getJavaKind(), displacement, (HotSpotResolvedObjectType) runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(obj.getClass()), obj, |
|
216 runtime.getHostJVMCIBackend().getMetaAccess()); |
|
217 JavaKind kind = field.getJavaKind(); |
|
218 switch (kind) { |
|
219 case Boolean: |
|
220 return JavaConstant.forBoolean(isVolatile ? UNSAFE.getBooleanVolatile(obj, displacement) : UNSAFE.getBoolean(obj, displacement)); |
|
221 case Byte: |
|
222 return JavaConstant.forByte(isVolatile ? UNSAFE.getByteVolatile(obj, displacement) : UNSAFE.getByte(obj, displacement)); |
|
223 case Char: |
|
224 return JavaConstant.forChar(isVolatile ? UNSAFE.getCharVolatile(obj, displacement) : UNSAFE.getChar(obj, displacement)); |
|
225 case Short: |
|
226 return JavaConstant.forShort(isVolatile ? UNSAFE.getShortVolatile(obj, displacement) : UNSAFE.getShort(obj, displacement)); |
|
227 case Int: |
|
228 return JavaConstant.forInt(isVolatile ? UNSAFE.getIntVolatile(obj, displacement) : UNSAFE.getInt(obj, displacement)); |
|
229 case Long: |
|
230 return JavaConstant.forLong(isVolatile ? UNSAFE.getLongVolatile(obj, displacement) : UNSAFE.getLong(obj, displacement)); |
|
231 case Float: |
|
232 return JavaConstant.forFloat(isVolatile ? UNSAFE.getFloatVolatile(obj, displacement) : UNSAFE.getFloat(obj, displacement)); |
|
233 case Double: |
|
234 return JavaConstant.forDouble(isVolatile ? UNSAFE.getDoubleVolatile(obj, displacement) : UNSAFE.getDouble(obj, displacement)); |
|
235 case Object: |
|
236 return HotSpotObjectConstantImpl.forObject(isVolatile ? UNSAFE.getReferenceVolatile(obj, displacement) : UNSAFE.getReference(obj, displacement)); |
|
237 default: |
|
238 throw new IllegalArgumentException("Unsupported kind: " + kind); |
|
239 } |
|
240 } |
150 } |
241 |
151 |
242 @Override |
152 @Override |
243 public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { |
153 public JavaConstant readPrimitiveConstant(JavaKind kind, Constant baseConstant, long initialDisplacement, int bits) { |
244 try { |
154 try { |
269 } |
179 } |
270 |
180 |
271 @Override |
181 @Override |
272 public JavaConstant readObjectConstant(Constant base, long displacement) { |
182 public JavaConstant readObjectConstant(Constant base, long displacement) { |
273 if (base instanceof HotSpotObjectConstantImpl) { |
183 if (base instanceof HotSpotObjectConstantImpl) { |
274 Object o = readRawObject(base, displacement, runtime.getConfig().useCompressedOops); |
184 return readRawObject(base, displacement, runtime.getConfig().useCompressedOops); |
275 return HotSpotObjectConstantImpl.forObject(o); |
185 } |
276 } |
186 if (!isValidObjectFieldDisplacement(base, displacement)) { |
277 if (base instanceof HotSpotMetaspaceConstant) { |
187 return null; |
278 MetaspaceWrapperObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
188 } |
279 if (metaspaceObject instanceof HotSpotResolvedObjectTypeImpl) { |
189 if (base instanceof HotSpotMetaspaceConstant && |
280 if (displacement == runtime.getConfig().classMirrorHandleOffset) { |
190 displacement == runtime.getConfig().javaMirrorOffset) { |
281 // Klass::_java_mirror is valid for all Klass* values |
191 MetaspaceObject metaspaceObject = HotSpotMetaspaceConstantImpl.getMetaspaceObject(base); |
282 return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror()); |
192 return ((HotSpotResolvedObjectTypeImpl) metaspaceObject).getJavaMirror(); |
283 } |
193 } |
284 } else { |
194 return readRawObject(base, displacement, false); |
285 throw new IllegalArgumentException(String.valueOf(metaspaceObject)); |
|
286 } |
|
287 } |
|
288 return null; |
|
289 } |
195 } |
290 |
196 |
291 @Override |
197 @Override |
292 public JavaConstant readNarrowOopConstant(Constant base, long displacement) { |
198 public JavaConstant readNarrowOopConstant(Constant base, long displacement) { |
293 return HotSpotObjectConstantImpl.forObject(readRawObject(base, displacement, true), true); |
199 JavaConstant res = readRawObject(base, displacement, true); |
|
200 return JavaConstant.NULL_POINTER.equals(res) ? HotSpotCompressedNullConstant.COMPRESSED_NULL : ((HotSpotObjectConstant) res).compress(); |
294 } |
201 } |
295 |
202 |
296 private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { |
203 private HotSpotResolvedObjectTypeImpl readKlass(Constant base, long displacement, boolean compressed) { |
297 assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); |
204 assert (base instanceof HotSpotMetaspaceConstantImpl) || (base instanceof HotSpotObjectConstantImpl) : base.getClass(); |
298 Object baseObject = (base instanceof HotSpotMetaspaceConstantImpl) ? ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType() : ((HotSpotObjectConstantImpl) base).object(); |
205 if (base instanceof HotSpotMetaspaceConstantImpl) { |
299 return runtime.getCompilerToVM().getResolvedJavaType(baseObject, displacement, compressed); |
206 return runtime.getCompilerToVM().getResolvedJavaType((HotSpotResolvedObjectTypeImpl) ((HotSpotMetaspaceConstantImpl) base).asResolvedJavaType(), displacement, compressed); |
300 } |
207 } else { |
|
208 return runtime.getCompilerToVM().getResolvedJavaType(((HotSpotObjectConstantImpl) base), displacement, compressed); |
|
209 } |
|
210 } |
|
211 |
301 |
212 |
302 @Override |
213 @Override |
303 public Constant readKlassPointerConstant(Constant base, long displacement) { |
214 public Constant readKlassPointerConstant(Constant base, long displacement) { |
304 HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); |
215 HotSpotResolvedObjectTypeImpl klass = readKlass(base, displacement, false); |
305 if (klass == null) { |
216 if (klass == null) { |