Mercurial > hg > graal-jvmci-8
comparison jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @ 22672:1bbd4a7c274b
Rename jdk.internal.jvmci to jdk.vm.ci
author | Tom Rodriguez <tom.rodriguez@oracle.com> |
---|---|
date | Thu, 08 Oct 2015 17:28:41 -0700 |
parents | jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java@ed53e370f04c |
children | 87394b31a42e |
comparison
equal
deleted
inserted
replaced
22671:97f30e4d0e95 | 22672:1bbd4a7c274b |
---|---|
1 /* | |
2 * Copyright (c) 2011, 2015, 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 package jdk.vm.ci.hotspot; | |
24 | |
25 import static java.util.Objects.requireNonNull; | |
26 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; | |
27 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; | |
28 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; | |
29 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; | |
30 | |
31 import java.lang.annotation.Annotation; | |
32 import java.lang.reflect.Array; | |
33 import java.lang.reflect.Constructor; | |
34 import java.lang.reflect.Method; | |
35 import java.lang.reflect.Modifier; | |
36 import java.net.URL; | |
37 import java.nio.ByteOrder; | |
38 import java.util.ArrayList; | |
39 import java.util.Arrays; | |
40 import java.util.HashMap; | |
41 | |
42 import jdk.vm.ci.common.JVMCIError; | |
43 import jdk.vm.ci.meta.Assumptions.AssumptionResult; | |
44 import jdk.vm.ci.meta.Assumptions.ConcreteMethod; | |
45 import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; | |
46 import jdk.vm.ci.meta.Assumptions.LeafType; | |
47 import jdk.vm.ci.meta.Assumptions.NoFinalizableSubclass; | |
48 import jdk.vm.ci.meta.Constant; | |
49 import jdk.vm.ci.meta.JavaConstant; | |
50 import jdk.vm.ci.meta.JavaKind; | |
51 import jdk.vm.ci.meta.JavaType; | |
52 import jdk.vm.ci.meta.MetaUtil; | |
53 import jdk.vm.ci.meta.ModifiersProvider; | |
54 import jdk.vm.ci.meta.ResolvedJavaField; | |
55 import jdk.vm.ci.meta.ResolvedJavaMethod; | |
56 import jdk.vm.ci.meta.ResolvedJavaType; | |
57 import jdk.vm.ci.meta.TrustedInterface; | |
58 | |
59 /** | |
60 * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. | |
61 */ | |
62 final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, HotSpotProxified, MetaspaceWrapperObject { | |
63 | |
64 /** | |
65 * The Java class this type represents. | |
66 */ | |
67 private final Class<?> javaClass; | |
68 private HashMap<Long, HotSpotResolvedJavaField> fieldCache; | |
69 private HashMap<Long, HotSpotResolvedJavaMethodImpl> methodCache; | |
70 private HotSpotResolvedJavaField[] instanceFields; | |
71 private HotSpotResolvedObjectTypeImpl[] interfaces; | |
72 private HotSpotConstantPool constantPool; | |
73 final HotSpotJVMCIMetaAccessContext context; | |
74 private HotSpotResolvedObjectType arrayOfType; | |
75 | |
76 /** | |
77 * Gets the JVMCI mirror for a {@link Class} object. | |
78 * | |
79 * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} | |
80 */ | |
81 static HotSpotResolvedObjectTypeImpl fromObjectClass(Class<?> javaClass) { | |
82 return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); | |
83 } | |
84 | |
85 /** | |
86 * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the | |
87 * underlying Klass*, it is used instead of the raw Klass*. | |
88 * | |
89 * Called from the VM. | |
90 * | |
91 * @param javaClass a {@link Class} object | |
92 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} | |
93 */ | |
94 @SuppressWarnings("unused") | |
95 private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class<?> javaClass) { | |
96 return fromObjectClass(javaClass); | |
97 } | |
98 | |
99 /** | |
100 * Creates the JVMCI mirror for a {@link Class} object. | |
101 * | |
102 * <p> | |
103 * <b>NOTE</b>: Creating an instance of this class does not install the mirror for the | |
104 * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} | |
105 * instead. | |
106 * </p> | |
107 * | |
108 * @param javaClass the Class to create the mirror for | |
109 * @param context | |
110 */ | |
111 HotSpotResolvedObjectTypeImpl(Class<?> javaClass, HotSpotJVMCIMetaAccessContext context) { | |
112 super(getSignatureName(javaClass)); | |
113 this.javaClass = javaClass; | |
114 this.context = context; | |
115 assert getName().charAt(0) != '[' || isArray() : getName(); | |
116 } | |
117 | |
118 /** | |
119 * Returns the name of this type as it would appear in a signature. | |
120 */ | |
121 private static String getSignatureName(Class<?> javaClass) { | |
122 if (javaClass.isArray()) { | |
123 return javaClass.getName().replace('.', '/'); | |
124 } | |
125 return "L" + javaClass.getName().replace('.', '/') + ";"; | |
126 } | |
127 | |
128 /** | |
129 * Gets the metaspace Klass for this type. | |
130 */ | |
131 long getMetaspaceKlass() { | |
132 if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { | |
133 return UNSAFE.getLong(javaClass, (long) config().klassOffset); | |
134 } | |
135 return UNSAFE.getInt(javaClass, (long) config().klassOffset) & 0xFFFFFFFFL; | |
136 } | |
137 | |
138 public long getMetaspacePointer() { | |
139 return getMetaspaceKlass(); | |
140 } | |
141 | |
142 @Override | |
143 public int getModifiers() { | |
144 if (isArray()) { | |
145 return (getElementalType().getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)) | Modifier.FINAL | Modifier.ABSTRACT; | |
146 } else { | |
147 return getAccessFlags() & ModifiersProvider.jvmClassModifiers(); | |
148 } | |
149 } | |
150 | |
151 public int getAccessFlags() { | |
152 HotSpotVMConfig config = config(); | |
153 return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); | |
154 } | |
155 | |
156 @Override | |
157 public HotSpotResolvedObjectType getArrayClass() { | |
158 if (arrayOfType == null) { | |
159 arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); | |
160 } | |
161 return arrayOfType; | |
162 } | |
163 | |
164 @Override | |
165 public ResolvedJavaType getComponentType() { | |
166 Class<?> javaComponentType = mirror().getComponentType(); | |
167 return javaComponentType == null ? null : runtime().fromClass(javaComponentType); | |
168 } | |
169 | |
170 @Override | |
171 public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() { | |
172 HotSpotVMConfig config = config(); | |
173 if (isArray()) { | |
174 return getElementalType().isLeaf() ? new AssumptionResult<>(this) : null; | |
175 } else if (isInterface()) { | |
176 HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); | |
177 /* | |
178 * If the implementor field contains itself that indicates that the interface has more | |
179 * than one implementors (see: InstanceKlass::add_implementor). | |
180 */ | |
181 if (implementor == null || implementor.equals(this)) { | |
182 return null; | |
183 } | |
184 | |
185 assert !implementor.isInterface(); | |
186 if (implementor.isAbstract() || !implementor.isLeafClass()) { | |
187 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = implementor.findLeafConcreteSubtype(); | |
188 if (leafConcreteSubtype != null) { | |
189 assert !leafConcreteSubtype.getResult().equals(implementor); | |
190 AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); | |
191 // Accumulate leaf assumptions and return the combined result. | |
192 newResult.add(leafConcreteSubtype); | |
193 return newResult; | |
194 } | |
195 return null; | |
196 } | |
197 | |
198 return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor)); | |
199 } else { | |
200 HotSpotResolvedObjectTypeImpl type = this; | |
201 while (type.isAbstract()) { | |
202 HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); | |
203 if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { | |
204 return null; | |
205 } | |
206 type = subklass; | |
207 } | |
208 if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { | |
209 return null; | |
210 } | |
211 if (this.isAbstract()) { | |
212 return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); | |
213 } else { | |
214 assert this.equals(type); | |
215 return new AssumptionResult<>(type, new LeafType(type)); | |
216 } | |
217 } | |
218 } | |
219 | |
220 /** | |
221 * Returns if type {@code type} is a leaf class. This is the case if the | |
222 * {@code Klass::_subklass} field of the underlying class is zero. | |
223 * | |
224 * @return true if the type is a leaf class | |
225 */ | |
226 private boolean isLeafClass() { | |
227 return getSubklass() == null; | |
228 } | |
229 | |
230 /** | |
231 * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given | |
232 * type {@code type}. | |
233 * | |
234 * @return value of the subklass field as metaspace klass pointer | |
235 */ | |
236 private HotSpotResolvedObjectTypeImpl getSubklass() { | |
237 return compilerToVM().getResolvedJavaType(this, config().subklassOffset, false); | |
238 } | |
239 | |
240 @Override | |
241 public HotSpotResolvedObjectTypeImpl getSuperclass() { | |
242 Class<?> javaSuperclass = mirror().getSuperclass(); | |
243 return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); | |
244 } | |
245 | |
246 @Override | |
247 public HotSpotResolvedObjectTypeImpl[] getInterfaces() { | |
248 if (interfaces == null) { | |
249 Class<?>[] javaInterfaces = mirror().getInterfaces(); | |
250 HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; | |
251 for (int i = 0; i < javaInterfaces.length; i++) { | |
252 result[i] = fromObjectClass(javaInterfaces[i]); | |
253 } | |
254 interfaces = result; | |
255 } | |
256 return interfaces; | |
257 } | |
258 | |
259 @Override | |
260 public HotSpotResolvedObjectTypeImpl getSingleImplementor() { | |
261 if (!isInterface()) { | |
262 throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); | |
263 } | |
264 return compilerToVM().getImplementor(this); | |
265 } | |
266 | |
267 public HotSpotResolvedObjectTypeImpl getSupertype() { | |
268 if (isArray()) { | |
269 ResolvedJavaType componentType = getComponentType(); | |
270 if (mirror() == Object[].class || componentType.isPrimitive()) { | |
271 return fromObjectClass(Object.class); | |
272 } | |
273 return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); | |
274 } | |
275 if (isInterface()) { | |
276 return fromObjectClass(Object.class); | |
277 } | |
278 return getSuperclass(); | |
279 } | |
280 | |
281 @Override | |
282 public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) { | |
283 if (otherType.isPrimitive()) { | |
284 return null; | |
285 } else { | |
286 HotSpotResolvedObjectTypeImpl t1 = this; | |
287 HotSpotResolvedObjectTypeImpl t2 = (HotSpotResolvedObjectTypeImpl) otherType; | |
288 while (true) { | |
289 if (t1.isAssignableFrom(t2)) { | |
290 return t1; | |
291 } | |
292 if (t2.isAssignableFrom(t1)) { | |
293 return t2; | |
294 } | |
295 t1 = t1.getSupertype(); | |
296 t2 = t2.getSupertype(); | |
297 } | |
298 } | |
299 } | |
300 | |
301 @Override | |
302 public HotSpotResolvedObjectType asExactType() { | |
303 return isLeaf() ? this : null; | |
304 } | |
305 | |
306 @Override | |
307 public JavaConstant getJavaClass() { | |
308 return HotSpotObjectConstantImpl.forObject(mirror()); | |
309 } | |
310 | |
311 @Override | |
312 public Constant getObjectHub() { | |
313 return klass(); | |
314 } | |
315 | |
316 @Override | |
317 public AssumptionResult<Boolean> hasFinalizableSubclass() { | |
318 assert !isArray(); | |
319 if (!compilerToVM().hasFinalizableSubclass(this)) { | |
320 return new AssumptionResult<>(false, new NoFinalizableSubclass(this)); | |
321 } | |
322 return new AssumptionResult<>(true); | |
323 } | |
324 | |
325 @Override | |
326 public boolean hasFinalizer() { | |
327 HotSpotVMConfig config = config(); | |
328 return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; | |
329 } | |
330 | |
331 @Override | |
332 public boolean isPrimitive() { | |
333 return false; | |
334 } | |
335 | |
336 @Override | |
337 public boolean isArray() { | |
338 return mirror().isArray(); | |
339 } | |
340 | |
341 @Override | |
342 public boolean isInitialized() { | |
343 return isArray() ? true : getInitState() == config().instanceKlassStateFullyInitialized; | |
344 } | |
345 | |
346 @Override | |
347 public boolean isLinked() { | |
348 return isArray() ? true : getInitState() >= config().instanceKlassStateLinked; | |
349 } | |
350 | |
351 /** | |
352 * Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace | |
353 * klass. | |
354 * | |
355 * @return state field value of this type | |
356 */ | |
357 private int getInitState() { | |
358 assert !isArray() : "_init_state only exists in InstanceKlass"; | |
359 return UNSAFE.getByte(getMetaspaceKlass() + config().instanceKlassInitStateOffset) & 0xFF; | |
360 } | |
361 | |
362 @Override | |
363 public void initialize() { | |
364 if (!isInitialized()) { | |
365 UNSAFE.ensureClassInitialized(mirror()); | |
366 assert isInitialized(); | |
367 } | |
368 } | |
369 | |
370 @Override | |
371 public boolean isInstance(JavaConstant obj) { | |
372 if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { | |
373 return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); | |
374 } | |
375 return false; | |
376 } | |
377 | |
378 @Override | |
379 public boolean isInstanceClass() { | |
380 return !isArray() && !isInterface(); | |
381 } | |
382 | |
383 @Override | |
384 public boolean isInterface() { | |
385 return mirror().isInterface(); | |
386 } | |
387 | |
388 @Override | |
389 public boolean isAssignableFrom(ResolvedJavaType other) { | |
390 assert other != null; | |
391 if (other instanceof HotSpotResolvedObjectTypeImpl) { | |
392 HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; | |
393 return mirror().isAssignableFrom(otherType.mirror()); | |
394 } | |
395 return false; | |
396 } | |
397 | |
398 @Override | |
399 public boolean isJavaLangObject() { | |
400 return javaClass.equals(Object.class); | |
401 } | |
402 | |
403 @Override | |
404 public JavaKind getJavaKind() { | |
405 return JavaKind.Object; | |
406 } | |
407 | |
408 @Override | |
409 public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { | |
410 ResolvedJavaMethod resolvedMethod = resolveMethod(method, callerType); | |
411 if (resolvedMethod == null || resolvedMethod.isAbstract()) { | |
412 return null; | |
413 } | |
414 return resolvedMethod; | |
415 } | |
416 | |
417 @Override | |
418 public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { | |
419 assert !callerType.isArray(); | |
420 if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic()) { | |
421 return method; | |
422 } | |
423 if (!method.getDeclaringClass().isAssignableFrom(this)) { | |
424 return null; | |
425 } | |
426 HotSpotResolvedJavaMethodImpl hotSpotMethod = (HotSpotResolvedJavaMethodImpl) method; | |
427 HotSpotResolvedObjectTypeImpl hotSpotCallerType = (HotSpotResolvedObjectTypeImpl) callerType; | |
428 return compilerToVM().resolveMethod(this, hotSpotMethod, hotSpotCallerType); | |
429 } | |
430 | |
431 public HotSpotConstantPool getConstantPool() { | |
432 if (constantPool == null) { | |
433 constantPool = compilerToVM().getConstantPool(this, config().instanceKlassConstantsOffset); | |
434 } | |
435 return constantPool; | |
436 } | |
437 | |
438 /** | |
439 * Gets the instance size of this type. If an instance of this type cannot be fast path | |
440 * allocated, then the returned value is negative (its absolute value gives the size). Must not | |
441 * be called if this is an array or interface type. | |
442 */ | |
443 public int instanceSize() { | |
444 assert !isArray(); | |
445 assert !isInterface(); | |
446 | |
447 HotSpotVMConfig config = config(); | |
448 final int layoutHelper = layoutHelper(); | |
449 assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; | |
450 | |
451 // See: Klass::layout_helper_size_in_bytes | |
452 int size = layoutHelper & ~config.klassLayoutHelperInstanceSlowPathBit; | |
453 | |
454 // See: Klass::layout_helper_needs_slow_path | |
455 boolean needsSlowPath = (layoutHelper & config.klassLayoutHelperInstanceSlowPathBit) != 0; | |
456 | |
457 return needsSlowPath ? -size : size; | |
458 } | |
459 | |
460 public int layoutHelper() { | |
461 HotSpotVMConfig config = config(); | |
462 return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); | |
463 } | |
464 | |
465 synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { | |
466 HotSpotResolvedJavaMethodImpl method = null; | |
467 if (methodCache == null) { | |
468 methodCache = new HashMap<>(8); | |
469 } else { | |
470 method = methodCache.get(metaspaceMethod); | |
471 } | |
472 if (method == null) { | |
473 method = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); | |
474 methodCache.put(metaspaceMethod, method); | |
475 context.add(method); | |
476 } | |
477 return method; | |
478 } | |
479 | |
480 public int getVtableLength() { | |
481 HotSpotVMConfig config = config(); | |
482 if (isInterface() || isArray()) { | |
483 /* Everything has the core vtable of java.lang.Object */ | |
484 return config.baseVtableLength; | |
485 } | |
486 int result = UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); | |
487 assert result >= config.baseVtableLength : UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize; | |
488 return result; | |
489 } | |
490 | |
491 public synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { | |
492 HotSpotResolvedJavaField result = null; | |
493 | |
494 final int flags = rawFlags & ModifiersProvider.jvmFieldModifiers(); | |
495 | |
496 final long id = offset + ((long) flags << 32); | |
497 | |
498 // Must cache the fields, because the local load elimination only works if the | |
499 // objects from two field lookups are identical. | |
500 if (fieldCache == null) { | |
501 fieldCache = new HashMap<>(8); | |
502 } else { | |
503 result = fieldCache.get(id); | |
504 } | |
505 | |
506 if (result == null) { | |
507 result = new HotSpotResolvedJavaFieldImpl(this, fieldName, type, offset, rawFlags); | |
508 fieldCache.put(id, result); | |
509 } else { | |
510 assert result.getName().equals(fieldName); | |
511 // assert result.getType().equals(type); | |
512 assert result.offset() == offset; | |
513 assert result.getModifiers() == flags; | |
514 } | |
515 | |
516 return result; | |
517 } | |
518 | |
519 @Override | |
520 public AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) { | |
521 HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; | |
522 HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); | |
523 /* | |
524 * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared | |
525 * holder, usually because of phis, so make sure that the type is related to the declared | |
526 * type before using it for lookup. Unlinked types should also be ignored because we can't | |
527 * resolve the proper method to invoke. Generally unlinked types in invokes should result in | |
528 * a deopt instead since they can't really be used if they aren't linked yet. | |
529 */ | |
530 if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { | |
531 ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); | |
532 if (result != null) { | |
533 return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); | |
534 } | |
535 return null; | |
536 } | |
537 /* | |
538 * The holder may be a subtype of the declaredHolder so make sure to resolve the method to | |
539 * the correct method for the subtype. | |
540 */ | |
541 HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); | |
542 if (resolvedMethod == null) { | |
543 // The type isn't known to implement the method. | |
544 return null; | |
545 } | |
546 | |
547 ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); | |
548 if (result != null) { | |
549 return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); | |
550 } | |
551 return null; | |
552 } | |
553 | |
554 /** | |
555 * This class represents the field information for one field contained in the fields array of an | |
556 * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. | |
557 */ | |
558 private class FieldInfo { | |
559 /** | |
560 * Native pointer into the array of Java shorts. | |
561 */ | |
562 private final long metaspaceData; | |
563 | |
564 /** | |
565 * Creates a field info for the field in the fields array at index {@code index}. | |
566 * | |
567 * @param index index to the fields array | |
568 */ | |
569 public FieldInfo(int index) { | |
570 HotSpotVMConfig config = config(); | |
571 // Get Klass::_fields | |
572 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); | |
573 assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; | |
574 metaspaceData = metaspaceFields + config.arrayU2DataOffset + config.fieldInfoFieldSlots * Short.BYTES * index; | |
575 } | |
576 | |
577 private int getAccessFlags() { | |
578 return readFieldSlot(config().fieldInfoAccessFlagsOffset); | |
579 } | |
580 | |
581 private int getNameIndex() { | |
582 return readFieldSlot(config().fieldInfoNameIndexOffset); | |
583 } | |
584 | |
585 private int getSignatureIndex() { | |
586 return readFieldSlot(config().fieldInfoSignatureIndexOffset); | |
587 } | |
588 | |
589 public int getOffset() { | |
590 HotSpotVMConfig config = config(); | |
591 final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); | |
592 final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); | |
593 final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; | |
594 return offset; | |
595 } | |
596 | |
597 /** | |
598 * Helper method to read an entry (slot) from the field array. Currently field info is laid | |
599 * on top an array of Java shorts. | |
600 */ | |
601 private int readFieldSlot(int index) { | |
602 return UNSAFE.getChar(metaspaceData + Short.BYTES * index); | |
603 } | |
604 | |
605 /** | |
606 * Returns the name of this field as a {@link String}. If the field is an internal field the | |
607 * name index is pointing into the vmSymbols table. | |
608 */ | |
609 public String getName() { | |
610 final int nameIndex = getNameIndex(); | |
611 return isInternal() ? HotSpotVmSymbols.symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); | |
612 } | |
613 | |
614 /** | |
615 * Returns the signature of this field as {@link String}. If the field is an internal field | |
616 * the signature index is pointing into the vmSymbols table. | |
617 */ | |
618 public String getSignature() { | |
619 final int signatureIndex = getSignatureIndex(); | |
620 return isInternal() ? HotSpotVmSymbols.symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); | |
621 } | |
622 | |
623 public JavaType getType() { | |
624 String signature = getSignature(); | |
625 return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); | |
626 } | |
627 | |
628 private boolean isInternal() { | |
629 return (getAccessFlags() & config().jvmAccFieldInternal) != 0; | |
630 } | |
631 | |
632 public boolean isStatic() { | |
633 return Modifier.isStatic(getAccessFlags()); | |
634 } | |
635 | |
636 public boolean hasGenericSignature() { | |
637 return (getAccessFlags() & config().jvmAccFieldHasGenericSignature) != 0; | |
638 } | |
639 } | |
640 | |
641 private static class OffsetComparator implements java.util.Comparator<HotSpotResolvedJavaField> { | |
642 @Override | |
643 public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { | |
644 return o1.offset() - o2.offset(); | |
645 } | |
646 } | |
647 | |
648 @Override | |
649 public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { | |
650 if (instanceFields == null) { | |
651 if (isArray() || isInterface()) { | |
652 instanceFields = new HotSpotResolvedJavaField[0]; | |
653 } else { | |
654 final int fieldCount = getFieldCount(); | |
655 ArrayList<HotSpotResolvedJavaField> fieldsArray = new ArrayList<>(fieldCount); | |
656 | |
657 for (int i = 0; i < fieldCount; i++) { | |
658 FieldInfo field = new FieldInfo(i); | |
659 | |
660 // We are only interested in instance fields. | |
661 if (!field.isStatic()) { | |
662 HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); | |
663 fieldsArray.add(resolvedJavaField); | |
664 } | |
665 } | |
666 | |
667 fieldsArray.sort(new OffsetComparator()); | |
668 | |
669 HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); | |
670 | |
671 if (mirror() != Object.class) { | |
672 HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); | |
673 HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); | |
674 System.arraycopy(myFields, 0, fields, superFields.length, myFields.length); | |
675 instanceFields = fields; | |
676 } else { | |
677 assert myFields.length == 0 : "java.lang.Object has fields!"; | |
678 instanceFields = myFields; | |
679 } | |
680 | |
681 } | |
682 } | |
683 if (!includeSuperclasses) { | |
684 int myFieldsStart = 0; | |
685 while (myFieldsStart < instanceFields.length && !instanceFields[myFieldsStart].getDeclaringClass().equals(this)) { | |
686 myFieldsStart++; | |
687 } | |
688 if (myFieldsStart == 0) { | |
689 return instanceFields; | |
690 } | |
691 if (myFieldsStart == instanceFields.length) { | |
692 return new HotSpotResolvedJavaField[0]; | |
693 } | |
694 return Arrays.copyOfRange(instanceFields, myFieldsStart, instanceFields.length); | |
695 } | |
696 return instanceFields; | |
697 } | |
698 | |
699 @Override | |
700 public ResolvedJavaField[] getStaticFields() { | |
701 if (isArray()) { | |
702 return new HotSpotResolvedJavaField[0]; | |
703 } else { | |
704 final int fieldCount = getFieldCount(); | |
705 ArrayList<HotSpotResolvedJavaField> fieldsArray = new ArrayList<>(fieldCount); | |
706 | |
707 for (int i = 0; i < fieldCount; i++) { | |
708 FieldInfo field = new FieldInfo(i); | |
709 | |
710 // We are only interested in static fields. | |
711 if (field.isStatic()) { | |
712 HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); | |
713 fieldsArray.add(resolvedJavaField); | |
714 } | |
715 } | |
716 | |
717 fieldsArray.sort(new OffsetComparator()); | |
718 return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]); | |
719 } | |
720 } | |
721 | |
722 /** | |
723 * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array | |
724 * by walking the array and discounting the generic signature slots at the end of the array. | |
725 * | |
726 * <p> | |
727 * See {@code FieldStreamBase::init_generic_signature_start_slot} | |
728 */ | |
729 private int getFieldCount() { | |
730 HotSpotVMConfig config = config(); | |
731 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); | |
732 int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); | |
733 int fieldCount = 0; | |
734 | |
735 for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { | |
736 FieldInfo field = new FieldInfo(index); | |
737 if (field.hasGenericSignature()) { | |
738 metaspaceFieldsLength--; | |
739 } | |
740 fieldCount++; | |
741 } | |
742 return fieldCount; | |
743 } | |
744 | |
745 @Override | |
746 public Class<?> mirror() { | |
747 return javaClass; | |
748 } | |
749 | |
750 @Override | |
751 public String getSourceFileName() { | |
752 HotSpotVMConfig config = config(); | |
753 final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); | |
754 if (sourceFileNameIndex == 0) { | |
755 return null; | |
756 } | |
757 return getConstantPool().lookupUtf8(sourceFileNameIndex); | |
758 } | |
759 | |
760 @Override | |
761 public Annotation[] getAnnotations() { | |
762 return mirror().getAnnotations(); | |
763 } | |
764 | |
765 @Override | |
766 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { | |
767 return mirror().getAnnotation(annotationClass); | |
768 } | |
769 | |
770 /** | |
771 * Performs a fast-path check that this type is resolved in the context of a given accessing | |
772 * class. A negative result does not mean this type is not resolved with respect to | |
773 * {@code accessingClass}. That can only be determined by | |
774 * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) | |
775 * re-resolving} the type. | |
776 */ | |
777 public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { | |
778 assert accessingClass != null; | |
779 ResolvedJavaType elementType = getElementalType(); | |
780 if (elementType.isPrimitive()) { | |
781 // Primitive type resolution is context free. | |
782 return true; | |
783 } | |
784 if (elementType.getName().startsWith("Ljava/")) { | |
785 // Classes in a java.* package can only be defined by the | |
786 // boot class loader. This is enforced by ClassLoader.preDefineClass() | |
787 assert mirror().getClassLoader() == null; | |
788 return true; | |
789 } | |
790 ClassLoader thisCl = mirror().getClassLoader(); | |
791 ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); | |
792 return thisCl == accessingClassCl; | |
793 } | |
794 | |
795 @Override | |
796 public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { | |
797 if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { | |
798 return this; | |
799 } | |
800 HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; | |
801 return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); | |
802 } | |
803 | |
804 /** | |
805 * Gets the metaspace Klass boxed in a {@link JavaConstant}. | |
806 */ | |
807 public Constant klass() { | |
808 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); | |
809 } | |
810 | |
811 public boolean isPrimaryType() { | |
812 return config().secondarySuperCacheOffset != superCheckOffset(); | |
813 } | |
814 | |
815 public int superCheckOffset() { | |
816 HotSpotVMConfig config = config(); | |
817 return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); | |
818 } | |
819 | |
820 public long prototypeMarkWord() { | |
821 HotSpotVMConfig config = config(); | |
822 if (isArray()) { | |
823 return config.arrayPrototypeMarkWord(); | |
824 } else { | |
825 return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); | |
826 } | |
827 } | |
828 | |
829 @Override | |
830 public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { | |
831 ResolvedJavaField[] declaredFields = getInstanceFields(true); | |
832 for (ResolvedJavaField field : declaredFields) { | |
833 HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; | |
834 long resolvedFieldOffset = resolvedField.offset(); | |
835 // @formatter:off | |
836 if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && | |
837 expectedEntryKind.isPrimitive() && | |
838 !expectedEntryKind.equals(JavaKind.Void) && | |
839 resolvedField.getJavaKind().isPrimitive()) { | |
840 resolvedFieldOffset += | |
841 resolvedField.getJavaKind().getByteCount() - | |
842 Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); | |
843 } | |
844 if (resolvedFieldOffset == offset) { | |
845 return field; | |
846 } | |
847 // @formatter:on | |
848 } | |
849 return null; | |
850 } | |
851 | |
852 @Override | |
853 public URL getClassFilePath() { | |
854 Class<?> cls = mirror(); | |
855 return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class"); | |
856 } | |
857 | |
858 @Override | |
859 public boolean isLocal() { | |
860 return mirror().isLocalClass(); | |
861 } | |
862 | |
863 @Override | |
864 public boolean isMember() { | |
865 return mirror().isMemberClass(); | |
866 } | |
867 | |
868 @Override | |
869 public HotSpotResolvedObjectTypeImpl getEnclosingType() { | |
870 final Class<?> encl = mirror().getEnclosingClass(); | |
871 return encl == null ? null : fromObjectClass(encl); | |
872 } | |
873 | |
874 @Override | |
875 public ResolvedJavaMethod[] getDeclaredConstructors() { | |
876 Constructor<?>[] constructors = mirror().getDeclaredConstructors(); | |
877 ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; | |
878 for (int i = 0; i < constructors.length; i++) { | |
879 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); | |
880 assert result[i].isConstructor(); | |
881 } | |
882 return result; | |
883 } | |
884 | |
885 @Override | |
886 public ResolvedJavaMethod[] getDeclaredMethods() { | |
887 Method[] methods = mirror().getDeclaredMethods(); | |
888 ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; | |
889 for (int i = 0; i < methods.length; i++) { | |
890 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); | |
891 assert !result[i].isConstructor(); | |
892 } | |
893 return result; | |
894 } | |
895 | |
896 public ResolvedJavaMethod getClassInitializer() { | |
897 return compilerToVM().getClassInitializer(this); | |
898 } | |
899 | |
900 @Override | |
901 public String toString() { | |
902 return "HotSpotType<" + getName() + ", resolved>"; | |
903 } | |
904 | |
905 @Override | |
906 public boolean isTrustedInterfaceType() { | |
907 return TrustedInterface.class.isAssignableFrom(mirror()); | |
908 } | |
909 } |