JVM解析Clss类的属性是在ClassFileParser的parse_fields方法,如下
void ClassFileParser::parse_fields(const ClassFileStream* const cfs,bool is_interface,FieldAllocationCount* const fac, ConstantPool* cp,const int cp_size,u2* const java_fields_count_ptr,TRAPS){
....
}
下面就parse_fields方法体的逻辑注拆解分析
- 从字节码文件流中获取2个字节,表示是字段的长度,
cfs->guarantee_more(2, CHECK); // length
const u2 length = cfs->get_u2_fast();
*java_fields_count_ptr = length;
- 调用JavaClasses的get_injected的方法获取内置类注入的字段属性。 total_fields总的属性个数=字节码的定义的属性个数+内置类注入的属性。
int num_injected = 0;
const InjectedField* const injected = JavaClasses::get_injected(_class_name, &num_injected);
const int total_fields = length + num_injected;
为field分配空间
- 调用NEW_RESOURCE_ARRAY_IN_THREAD宏定义在线程resourceArea临时分配分配数组资源,是为了生成field的signature index(签名索引),解析完后,会拷贝到持久化的素组,同样会利用ResourceMark的析构函数去释放不再使用的空间。
ResourceMark rm(THREAD);
u2* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
u2,total_fields * (FieldInfo::field_slots + 1));
//share/memory/allocation.hpp中宏定义
#define NEW_RESOURCE_ARRAY_IN_THREAD(thread, type, size)\
(type*) resource_allocate_bytes(thread, (size) * sizeof(type))
//share/memory/resourceArea.cpp中resource_allocate_bytes方法
extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType alloc_failmode) {
return thread->resource_area()->allocate_bytes(size, alloc_failmode);
}
// share/oops/fieldInfo.hpp
enum FieldOffset {
access_flags_offset = 0,
name_index_offset = 1,
signature_index_offset = 2,
initval_index_offset = 3,
low_packed_offset = 4,
high_packed_offset = 5,
field_slots = 6
};
字节码的field保存的信息如下
解析字节码文件的field信息保存到_field数组
- 接下来就是for循环遍历解析字节码保存的Field信息。
//计算总的泛型签名的slot的数量,一个slot是2个字节
int generic_signature_slot = total_fields * FieldInfo::field_slots;
// 泛型签名的个数
int num_generic_signature = 0;
//循环遍历field的长度,解析字节码文件的field信息
for (int n = 0; n < length; n++) {
// access_flags, name_index, descriptor_index, attributes_count
cfs->guarantee_more(8, CHECK);
AccessFlags access_flags;
// 获取字段访问标识
const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
// 校验访问标识符
verify_legal_field_modifiers(flags, is_interface, CHECK);
access_flags.set_flags(flags);
// 获取常量池的名称索引
const u2 name_index = cfs->get_u2_fast();
// 校验名字索引长度
check_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for field name in class file %s",
name_index, CHECK);
// 获取常量池的名臣
const Symbol* const name = cp->symbol_at(name_index);
//校验字段名字的合法性
verify_legal_field_name(name, CHECK);
//获取签名的索引
const u2 signature_index = cfs->get_u2_fast();
//校验索引长度 check_property(valid_symbol_at(signature_index),"Invalid constant pool index %u for field signature in class file %s",
signature_index, CHECK);
//校验字段的签名
const Symbol* const sig = cp->symbol_at(signature_index);
//校验字段的签名
verify_legal_field_signature(name, sig, CHECK);
u2 constantvalue_index = 0;
bool is_synthetic = false;
u2 generic_signature_index = 0;
// 获取字段是否静态
const bool is_static = access_flags.is_static();
FieldAnnotationCollector parsed_annotations(_loader_data);
// 获取属性的个数
const u2 attributes_count = cfs->get_u2_fast();
if (attributes_count > 0) {
//解析字段属性
parse_field_attributes(cfs, attributes_count,
is_static,signature_index,&constantvalue_index,&is_synthetic,
&generic_signature_index,&parsed_annotations,CHECK);
// 解析字段的annotation注解
if (parsed_annotations.field_annotations() != NULL) {
if (_fields_annotations == NULL) {
_fields_annotations = MetadataFactory::new_array<AnnotationArray*>( _loader_data, length, NULL, CHECK);
}
_fields_annotations->at_put(n, parsed_annotations.field_annotations());
parsed_annotations.set_field_annotations(NULL);
}
if (parsed_annotations.field_type_annotations() != NULL) {
if (_fields_type_annotations == NULL) {
_fields_type_annotations =
MetadataFactory::new_array<AnnotationArray*>(_loader_data,length, NULL, CHECK);
}
_fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations());
parsed_annotations.set_field_type_annotations(NULL);
}
//是否編譯器生成的
if (is_synthetic) {
access_flags.set_is_synthetic();
}
//计算泛型签名索引
if (generic_signature_index != 0) {
access_flags.set_field_has_generic_signature();
fa[generic_signature_slot] = generic_signature_index;
generic_signature_slot ++;
num_generic_signature ++;
}
}
//创建FieldInfo对象
FieldInfo* const field = FieldInfo::from_field_array(fa, n);
//field的初始化
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index);
//签名的类型
const BasicType type = cp->basic_type_for_signature_at(signature_index);
// 更新FieldAllocationCount
fac->update(is_static, type);
// 初始化字段的属性
if (parsed_annotations.has_any_annotations()) {
parsed_annotations.apply_to(field);
if (field->is_contended()) {
_has_contended_fields = true;
}
}
}
- 然后判断注入的field个数大于0,则执行for循环遍历注入field的属性信息。
int index = length;
// 判断注入的field个数大于0
if (num_injected != 0) {
// for循环遍历处理注入的field
for (int n = 0; n < num_injected; n++) {
// 判断java定义和内置定义注入的属性是否重复是否重复
if (injected[n].may_be_java) {
const Symbol* const name = injected[n].name();
const Symbol* const signature = injected[n].signature();
bool duplicate = false;
for (int i = 0; i < length; i++) {
const FieldInfo* const f = FieldInfo::from_field_array(fa, i);
if (name == cp->symbol_at(f->name_index()) &&
signature == cp->symbol_at(f->signature_index())) {
//如果跟java定义的重复则删掉
duplicate = true;
break;
}
}
if (duplicate) {
// 重复则直接跳过
continue;
}
}
// 获取注入的field
FieldInfo* const field = FieldInfo::from_field_array(fa, index);
//Field初始化
field->initialize((u2)JVM_ACC_FIELD_INTERNAL,
(u2)(injected[n].name_index),
(u2)(injected[n].signature_index),
0);
const BasicType type = Signature::basic_type(injected[n].signature());
// 更新FieldAllocationCount
fac->update(false, type);
index++;
}
}
//在元空间分配数组空间存储解析后的field信息
_fields =
MetadataFactory::new_array<u2>(_loader_data,
index * FieldInfo::field_slots + num_generic_signature,
CHECK);
{
int i = 0;
//循环遍历将份fa的临时数据存在_field数组中,
for (; i < index * FieldInfo::field_slots; i++) {
_fields->at_put(i, fa[i]);
}
//处理泛型签名的slot,放在_fields数组的后面
for (int j = total_fields * FieldInfo::field_slots;
j < generic_signature_slot; j++) {
_fields->at_put(i++, fa[j]);
}
assert(_fields->length() == i, "");
}
//判断field个数大于1,则判断重复field
if (_need_verify && length > 1) {
//创建resouceMark对象.标识线程分配的资源,在析构函数中释放资源
ResourceMark rm(THREAD);
//NEW_RESOURCE_ARRAY_IN_THREAD宏定义在线程ReourceArea中分配默认是256个NameSigHash对象大小的空间
NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, NameSigHash*, HASH_ROW_SIZE);
//初始化内存的值为0
initialize_hashtable(names_and_sigs);
bool dup = false;
const Symbol* name = NULL;
const Symbol* sig = NULL;
{
// 循环遍历java定义的field和注入的内置属性,然后判断是否重复
for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
name = fs.name();
sig = fs.signature();
// 使用hash表+链条的方法,判断是否field重复
if (!put_after_lookup(name, sig, names_and_sigs)) {
dup = true;
break;
}
}
}
//字段重复抛出异常
if (dup) {
classfile_parse_error("Duplicate field name \"%s\" with signature \"%s\" in class file %s",
name->as_C_string(), sig->as_klass_external_name(), THREAD);
}
}
最终field的short数组存储方式如下
f1: [access, name index, sig index, initial value index, low_offset, high_offset]
f2: [access, name index, sig index, initial value index, low_offset, high_offset]
...
fn: [access, name index, sig index, initial value index, low_offset, high_offset]
[generic signature index]
[generic signature index]
总结
今天主要就是JVM的Field的访问标识、名称、字段属性例如泛型等解析和校验,以及对于JDK的内部类的的注入
field的重复判断。