Mercurial > hg > graal-compiler
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 } |