JVM类解析之Field属性解析(二)

187 阅读4分钟

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方法体的逻辑注拆解分析

  1. 从字节码文件流中获取2个字节,表示是字段的长度,
  cfs->guarantee_more(2, CHECK);  // length
  const u2 length = cfs->get_u2_fast();
  *java_fields_count_ptr = length;
  1. 调用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分配空间

  1. 调用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保存的信息如下 image.png

解析字节码文件的field信息保存到_field数组

  1. 接下来就是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;
      }
    }
  }
  1. 然后判断注入的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的重复判断。