comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotResolvedObjectTypeImpl.java @ 21551:5324104ac4f3

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