150 HotSpotVMConfig config = config(); 151 return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); 152 } 153 154 @Override 155 public HotSpotResolvedObjectType getArrayClass() { 156 if (arrayOfType == null) { 157 arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); 158 } 159 return arrayOfType; 160 } 161 162 @Override 163 public ResolvedJavaType getComponentType() { 164 Class<?> javaComponentType = mirror().getComponentType(); 165 return javaComponentType == null ? null : runtime().fromClass(javaComponentType); 166 } 167 168 @Override 169 public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() { 170 HotSpotVMConfig config = config(); 171 if (isArray()) { 172 return getElementalType().isLeaf() ? new AssumptionResult<>(this) : null; 173 } else if (isInterface()) { 174 HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); 175 /* 176 * If the implementor field contains itself that indicates that the interface has more 177 * than one implementors (see: InstanceKlass::add_implementor). 178 */ 179 if (implementor == null || implementor.equals(this)) { 180 return null; 181 } 182 183 assert !implementor.isInterface(); 184 if (implementor.isAbstract() || !implementor.isLeafClass()) { 185 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = implementor.findLeafConcreteSubtype(); 186 if (leafConcreteSubtype != null) { 187 assert !leafConcreteSubtype.getResult().equals(implementor); 188 AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); 189 // Accumulate leaf assumptions and return the combined result. 190 newResult.add(leafConcreteSubtype); 191 return newResult; 192 } 193 return null; 194 } 195 196 return new AssumptionResult<>(implementor, new LeafType(implementor), new ConcreteSubtype(this, implementor)); 197 } else { 198 HotSpotResolvedObjectTypeImpl type = this; 199 while (type.isAbstract()) { 200 HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); 201 if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { 202 return null; 203 } 204 type = subklass; 205 } 206 if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { 207 return null; 208 } 209 if (this.isAbstract()) { 210 return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); 211 } else { 212 assert this.equals(type); 213 return new AssumptionResult<>(type, new LeafType(type)); 214 } 215 } 216 } 217 218 /** 219 * Returns if type {@code type} is a leaf class. This is the case if the 220 * {@code Klass::_subklass} field of the underlying class is zero. 221 * 222 * @return true if the type is a leaf class 223 */ 224 private boolean isLeafClass() { 225 return getSubklass() == null; 226 } 227 228 /** 229 * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given 230 * type {@code type}. 231 * 232 * @return value of the subklass field as metaspace klass pointer 233 */ 234 private HotSpotResolvedObjectTypeImpl getSubklass() { 235 return compilerToVM().getResolvedJavaType(this, config().subklassOffset, false); 236 } 237 | 150 HotSpotVMConfig config = config(); 151 return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); 152 } 153 154 @Override 155 public HotSpotResolvedObjectType getArrayClass() { 156 if (arrayOfType == null) { 157 arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); 158 } 159 return arrayOfType; 160 } 161 162 @Override 163 public ResolvedJavaType getComponentType() { 164 Class<?> javaComponentType = mirror().getComponentType(); 165 return javaComponentType == null ? null : runtime().fromClass(javaComponentType); 166 } 167 168 @Override 169 public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() { 170 if (isLeaf()) { 171 // No assumptions are required. 172 return new AssumptionResult<>(this); 173 } 174 HotSpotVMConfig config = config(); 175 if (isArray()) { 176 ResolvedJavaType elementalType = getElementalType(); 177 AssumptionResult<ResolvedJavaType> elementType = elementalType.findLeafConcreteSubtype(); 178 if (elementType != null && elementType.getResult().equals(elementalType)) { 179 /* 180 * If the elementType is leaf then the array is leaf under the same assumptions but 181 * only if the element type is exactly the leaf type. The element type can be 182 * abstract even if there is only one implementor of the abstract type. 183 */ 184 AssumptionResult<ResolvedJavaType> result = new AssumptionResult<>(this); 185 result.add(elementType); 186 return result; 187 } 188 return null; 189 } else if (isInterface()) { 190 HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); 191 /* 192 * If the implementor field contains itself that indicates that the interface has more 193 * than one implementors (see: InstanceKlass::add_implementor). 194 */ 195 if (implementor == null || implementor.equals(this)) { 196 return null; 197 } 198 199 assert !implementor.isInterface(); 200 if (implementor.isAbstract() || !implementor.isLeafClass()) { 201 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = implementor.findLeafConcreteSubtype(); 202 if (leafConcreteSubtype != null) { 203 assert !leafConcreteSubtype.getResult().equals(implementor); 204 AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); 205 // Accumulate leaf assumptions and return the combined result. 206 newResult.add(leafConcreteSubtype); 207 return newResult; 208 } 209 return null; 210 } 211 return concreteSubtype(implementor); 212 } else { 213 HotSpotResolvedObjectTypeImpl type = this; 214 while (type.isAbstract()) { 215 HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); 216 if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { 217 return null; 218 } 219 type = subklass; 220 } 221 if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { 222 return null; 223 } 224 if (this.isAbstract()) { 225 return concreteSubtype(type); 226 } else { 227 assert this.equals(type); 228 return new AssumptionResult<>(type, new LeafType(type)); 229 } 230 } 231 } 232 233 private AssumptionResult<ResolvedJavaType> concreteSubtype(HotSpotResolvedObjectTypeImpl type) { 234 if (type.isLeaf()) { 235 return new AssumptionResult<>(type, new ConcreteSubtype(this, type)); 236 } else { 237 return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); 238 } 239 } 240 241 /** 242 * Returns if type {@code type} is a leaf class. This is the case if the 243 * {@code Klass::_subklass} field of the underlying class is zero. 244 * 245 * @return true if the type is a leaf class 246 */ 247 private boolean isLeafClass() { 248 return getSubklass() == null; 249 } 250 251 /** 252 * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given 253 * type {@code type}. 254 * 255 * @return value of the subklass field as metaspace klass pointer 256 */ 257 private HotSpotResolvedObjectTypeImpl getSubklass() { 258 return compilerToVM().getResolvedJavaType(this, config().subklassOffset, false); 259 } 260 |