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 }