zoukankan      html  css  js  c++  java
  • jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处

    之前分析的已经加载的.Class文件中都没有Static 静态变量,所以也就没这部分的解析,自己也是不懂hotspot 将静态变量放哪里去了,追踪源码之后,看清楚了整个套路,总体上来说,可以举例来说对于,java.lang.String的Class文件进行解析,String类有5个变量,其中有俩个静态变量

    private final char value[];
    
        private int hash; // Default to 0
        private static final long serialVersionUID = -6849794470754667710L;
        private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];
        public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                             = new CaseInsensitiveComparator();
        private static class CaseInsensitiveComparator
                implements Comparator<String>, java.io.Serializable {
            // use serialVersionUID from JDK 1.2.2 for interoperability
            private static final long serialVersionUID = 8575799808933029326L;
    
            public int compare(String s1, String s2) {
                int n1 = s1.length();
                int n2 = s2.length();
                int min = Math.min(n1, n2);
                for (int i = 0; i < min; i++) {
                    char c1 = s1.charAt(i);
                    char c2 = s2.charAt(i);
                    if (c1 != c2) {
                        c1 = Character.toUpperCase(c1);
                        c2 = Character.toUpperCase(c2);
                        if (c1 != c2) {
                            c1 = Character.toLowerCase(c1);
                            c2 = Character.toLowerCase(c2);
                            if (c1 != c2) {
                                // No overflow because of numeric promotion
                                return c1 - c2;
                            }
                        }
                    }
                }
                return n1 - n2;
            }
    
            /** Replaces the de-serialized object. */
            private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
        }

    看到了有5个成员变量

    private final char value[];
    private int hash;
    private static final long serialVersionUID = -6849794470754667710L;
    private static final ObjectStreamField[] serialPersistentFields =
            new ObjectStreamField[0];
        public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                             = new CaseInsensitiveComparator();
    第5个是一个内部类
    private static class CaseInsensitiveComparator

    先补充好,常量池的解析Field这部分知识

    先看jvm规范对于field的定义

    The structure has the following format:
    field_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
    }

    Table 4.5-A. Field access and property flags

    Flag Name Value Interpretation
    ACC_PUBLIC 0x0001 Declared public; may be accessed from outside itspackage.
    ACC_PRIVATE 0x0002 Declared private; usable only within the definingclass.
    ACC_PROTECTED 0x0004 Declared protected; may be accessed withinsubclasses.
    ACC_STATIC 0x0008 Declared static.
    ACC_FINAL 0x0010 Declared final; never directly assigned to afterobject construction (JLS §17.5).
    ACC_VOLATILE 0x0040 Declared volatile; cannot be cached.
    ACC_TRANSIENT 0x0080 Declared transient; not written or read by apersistent object manager.
    ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code.
    ACC_ENUM 0x4000 Declared as an element of an enum.

    对这四部分进行说明

    • access_flags

      • 说明,这个是变量的访问标识符,包含了,public private static ,final,voliat等,已经组合
    • name_index

      • 便是变量的名字,指向常量池    

    • descriptor_index

      • 表示变量的类型信息 如int long  Object ,ArrayType 等,下边的表中列出来BCDIJLSZ[ 等
    • attributes_count

      • 属性值 

    • attribute_info attributes[attributes_count];

      • 属性,这里主要介绍 ConstantValue这个属性

           

          

    Table 4.3-A. Interpretation of field descriptors

    FieldType term Type Interpretation
    B byte signed byte
    C char Unicode character code point in the Basic
    Multilingual Plane, encoded with UTF-16
    D double double-precision floating-point value
    F float single-precision floating-point value
    I int integer
    J long long integer
    L ClassName ; reference an instance of class ClassName
    S short signed short
    Z boolean true or false
    [ reference one array dimension

    ConstantValue这个属性

    The ConstantValue attribute has the following format:
      ConstantValue_attribute {
        u2 attribute_name_index;
        u4 attribute_length;
        u2 constantvalue_index;
      }
    The items of the ConstantValue_attribute structure are as follows:
      attribute_name_index
        The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index 

        must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string"ConstantValue".
      attribute_length
        The value of the attribute_length item of a ConstantValue_attribute structure must be two.
      constantvalue_index
    The value of the constantvalue_index item must be a valid index intothe constant_pool table. The constant_pool entry at that index gives the
    constant value represented by this attribute. The constant_pool entry must beof a type appropriate to the field, as specified in Table 4.7.2-A.
    Table 4.7.2-A. Constant value attribute types

    Field Type Entry Type
    long CONSTANT_Long
    float CONSTANT_Float
    double CONSTANT_Double
    int, short, char, byte, boolean CONSTANT_Integer
    String CONSTANT_String

    说的很清楚了,这个值需要是上述表格的中的类型

    那就拿一个例子出来

    这个field 共有5个,这个是第三个.

    那么分析:

    1. access_flags 是private static final
    2. 属性名字叫serialVersionUID,156是是常量池的索引
    3. descriptor_index  是J  那么解析出来就是LONG类型
    4. 有一个ConatantValue的属性
      1.  158 就是 ConatantValue
      2. attribte_length 必须是2
      3. 值的索引指向159,可以看到159是LONG类型的负数

    那么hotspot中如何解析的呢?

    在classFileParse.cpp中
    
        u2 java_fields_count = 0;
        // Fields (offsets are filled in later)
        FieldAllocationCount fac;
        Array<u2>* fields = parse_fields(class_name,
                                         access_flags.is_interface(),
                                         &fac, &java_fields_count,
                                         CHECK_(nullHandle));

    这里就不粘贴源码了,附带参考书中的解释

    这就清晰的过程,最后得到_short变得就是以下结构

    $49 = {26, 156, 157, 159, 33, 0}

    class FieldInfo VALUE_OBJ_CLASS_SPEC {
     
      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
      };
    
     private:
      u2 _shorts[field_slots];
    }

    解析的变量信息,那就解析一下子

    Array<u2>* ClassFileParser::parse_fields(Symbol* class_name,
                                             bool is_interface,
                                             FieldAllocationCount *fac,
                                             u2* java_fields_count_ptr, TRAPS) {
      ClassFileStream* cfs = stream();
      cfs->guarantee_more(2, CHECK_NULL);  // length
      u2 length = cfs->get_u2_fast();
      *java_fields_count_ptr = length;
    
      int num_injected = 0;
      InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected);
      int total_fields = length + num_injected;
    
      // The field array starts with tuples of shorts   说明field array 由 shorts类型的元组组成,每个分别是
      // [access, name index, sig index, initial value index, byte offset].
      // A generic signature slot only exists for field with generic
      // signature attribute. And the access flag is set with
      // JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic
      // signature slots are at the end of the field array and after all
      // other fields data.
      //
      //   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]
      //       ...
      //
      // Allocate a temporary resource array for field data. For each field,
      // a slot is reserved in the temporary array for the generic signature
      // index. After parsing all fields, the data are copied to a permanent
      // array and any unused slots will be discarded.
      ResourceMark rm(THREAD);
      u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD(
                 THREAD, u2, total_fields * (FieldInfo::field_slots + 1));
    
      // The generic signature slots start after all other fields' data.
      int generic_signature_slot = total_fields * FieldInfo::field_slots;
      int num_generic_signature = 0;
      for (int n = 0; n < length; n++) {
        cfs->guarantee_more(8, CHECK_NULL);  // access_flags, name_index, descriptor_index, attributes_count
    
        AccessFlags access_flags;
        jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
        verify_legal_field_modifiers(flags, is_interface, CHECK_NULL);
        access_flags.set_flags(flags);
    
        u2 name_index = cfs->get_u2_fast();
        int cp_size = _cp->length();
        check_property(valid_symbol_at(name_index),
          "Invalid constant pool index %u for field name in class file %s",
          name_index,
          CHECK_NULL);
        Symbol*  name = _cp->symbol_at(name_index);
        verify_legal_field_name(name, CHECK_NULL);
    
        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_NULL);
        Symbol*  sig = _cp->symbol_at(signature_index);
        verify_legal_field_signature(name, sig, CHECK_NULL);
    
        u2 constantvalue_index = 0;
        bool is_synthetic = false;
        u2 generic_signature_index = 0;
        bool is_static = access_flags.is_static();
        FieldAnnotationCollector parsed_annotations(_loader_data);
    
        u2 attributes_count = cfs->get_u2_fast();
        if (attributes_count > 0) {
          parse_field_attributes(attributes_count, is_static, signature_index,
                                 &constantvalue_index, &is_synthetic,
                                 &generic_signature_index, &parsed_annotations,
                                 CHECK_NULL);
          if (parsed_annotations.field_annotations() != NULL) {
            if (_fields_annotations == NULL) {
              _fields_annotations = MetadataFactory::new_array<AnnotationArray*>(
                                                 _loader_data, length, NULL,
                                                 CHECK_NULL);
            }
            _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_NULL);
            }
            _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* field = FieldInfo::from_field_array(fa, n);
        field->initialize(access_flags.as_short(),
                          name_index,
                          signature_index,
                          constantvalue_index);

    那么进入 field->initialize

      void initialize(u2 access_flags,
                      u2 name_index,
                      u2 signature_index,
                      u2 initval_index) {
        _shorts[access_flags_offset] = access_flags;
        _shorts[name_index_offset] = name_index;
        _shorts[signature_index_offset] = signature_index;
        _shorts[initval_index_offset] = initval_index;
        _shorts[low_packed_offset] = 0;
        _shorts[high_packed_offset] = 0;
      }

    上述就是,看initval_index这个就是初始值,就是默认值

    最终的field其实是这个东西

    (gdb) p _shorts
    $20 = {18, 152, 153, 0, 0, 0}

    BasicType type = _cp->basic_type_for_signature_at(signature_index);

    获取变量值

    转换

    // Convert a char from a classfile signature to a BasicType
    inline BasicType char2type(char c) {
      switch( c ) {
      case 'B': return T_BYTE;
      case 'C': return T_CHAR;
      case 'D': return T_DOUBLE;
      case 'F': return T_FLOAT;
      case 'I': return T_INT;
      case 'J': return T_LONG;
      case 'S': return T_SHORT;
      case 'Z': return T_BOOLEAN;
      case 'V': return T_VOID;
      case 'L': return T_OBJECT;
      case '[': return T_ARRAY;
      }
      return T_ILLEGAL;
    }

    计算每种类型的变量总量

        // Remember how many oops we encountered and compute allocation type
        FieldAllocationType atype = fac->update(is_static, type);
    
      FieldAllocationType update(bool is_static, BasicType type) {
        FieldAllocationType atype = basic_type_to_atype(is_static, type);
        // Make sure there is no overflow with injected fields.
        assert(count[atype] < 0xFFFF, "More than 65535 fields");
        count[atype]++;
        return atype;
      }

    查看

    (gdb) p atype
    $21 = NONSTATIC_OOP

      void set_allocation_type(int type) {  //type=5
        u2 lo = _shorts[low_packed_offset];
        switch(lo & FIELDINFO_TAG_MASK) {
          case FIELDINFO_TAG_BLANK:
            _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF;
            _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK;
            _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN;
            return;
    
      }

    (gdb) p _shorts
    $22 = {18, 152, 153, 0, 22, 0}

    看出来将第5位置设置为0到22 即为0x16

    那么

      // Packed field has the tag, and can be either of:
      //    hi bits <--------------------------- lo bits
      //   |---------high---------|---------low---------|
      //    ..........................................00  - blank
      //    [------------------offset----------------]01  - real field offset
      //    ......................[-------type-------]10  - plain field with type
      //    [--contention_group--][-------type-------]11  - contended field with type and contention group

    二进制为10110 那么这个就解析为 plain field with type, 这个5  就是

    (gdb) p atype
    $21 = NONSTATIC_OOP

    enum FieldAllocationType {
      STATIC_OOP,           // Oops
      STATIC_BYTE,          // Boolean, Byte, char
      STATIC_SHORT,         // shorts
      STATIC_WORD,          // ints
      STATIC_DOUBLE,        // aligned long or double
      NONSTATIC_OOP,
      NONSTATIC_BYTE,
      NONSTATIC_SHORT,
      NONSTATIC_WORD,
      NONSTATIC_DOUBLE,
      MAX_FIELD_ALLOCATION_TYPE,
      BAD_ALLOCATION_TYPE = -1
    };

    这就存在一个转换过程

    FieldAllocationType atype = fac->update(is_static, type);
    
      FieldAllocationType update(bool is_static, BasicType type) {
        FieldAllocationType atype = basic_type_to_atype(is_static, type);
        // Make sure there is no overflow with injected fields.
        assert(count[atype] < 0xFFFF, "More than 65535 fields");
        count[atype]++;
        return atype;
      }
    
    static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
      assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values");
      FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)];
      assert(result != BAD_ALLOCATION_TYPE, "bad type");
      return result;
    }
    
    static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = {
      BAD_ALLOCATION_TYPE, // 0
      BAD_ALLOCATION_TYPE, // 1
      BAD_ALLOCATION_TYPE, // 2
      BAD_ALLOCATION_TYPE, // 3
      NONSTATIC_BYTE ,     // T_BOOLEAN     =  4,
      NONSTATIC_SHORT,     // T_CHAR        =  5,
      NONSTATIC_WORD,      // T_FLOAT       =  6,
      NONSTATIC_DOUBLE,    // T_DOUBLE      =  7,
      NONSTATIC_BYTE,      // T_BYTE        =  8,
      NONSTATIC_SHORT,     // T_SHORT       =  9,
      NONSTATIC_WORD,      // T_INT         = 10,
      NONSTATIC_DOUBLE,    // T_LONG        = 11,
      NONSTATIC_OOP,       // T_OBJECT      = 12,
      NONSTATIC_OOP,       // T_ARRAY       = 13,
      BAD_ALLOCATION_TYPE, // T_VOID        = 14,
      BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
      BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
      BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
      BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
      BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
      BAD_ALLOCATION_TYPE, // 0
      BAD_ALLOCATION_TYPE, // 1
      BAD_ALLOCATION_TYPE, // 2
      BAD_ALLOCATION_TYPE, // 3
      STATIC_BYTE ,        // T_BOOLEAN     =  4,
      STATIC_SHORT,        // T_CHAR        =  5,
      STATIC_WORD,         // T_FLOAT       =  6,
      STATIC_DOUBLE,       // T_DOUBLE      =  7,
      STATIC_BYTE,         // T_BYTE        =  8,
      STATIC_SHORT,        // T_SHORT       =  9,
      STATIC_WORD,         // T_INT         = 10,
      STATIC_DOUBLE,       // T_LONG        = 11,
      STATIC_OOP,          // T_OBJECT      = 12,
      STATIC_OOP,          // T_ARRAY       = 13,
      BAD_ALLOCATION_TYPE, // T_VOID        = 14,
      BAD_ALLOCATION_TYPE, // T_ADDRESS     = 15,
      BAD_ALLOCATION_TYPE, // T_NARROWOOP   = 16,
      BAD_ALLOCATION_TYPE, // T_METADATA    = 17,
      BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
      BAD_ALLOCATION_TYPE, // T_CONFLICT    = 19,
    };

    完成了第一个变量的解析,现在执行到第三变量的解析 serialVersionUID ,他比前两个多了一个常数属性,那么主要看这个常数的解析

    if (attributes_count > 0) {
          parse_field_attributes(attributes_count, is_static, signature_index,
                                 &constantvalue_index, &is_synthetic,
                                 &generic_signature_index, &parsed_annotations,
                                 CHECK_NULL);
    ...}

    再看

    //主干
    void ClassFileParser::parse_field_attributes(u2 attributes_count,
                                                 bool is_static, u2 signature_index,
                                                 u2* constantvalue_index_addr,
                                                 bool* is_synthetic_addr,
                                                 u2* generic_signature_index_addr,
                                                 ClassFileParser::FieldAnnotationCollector* parsed_annotations,
                                                 TRAPS) {
    
    ...
      *constantvalue_index_addr = constantvalue_index;
      *is_synthetic_addr = is_synthetic;
      *generic_signature_index_addr = generic_signature_index;
    ..}

    接着就是初始化field变量

        FieldInfo* field = FieldInfo::from_field_array(fa, n);
        field->initialize(access_flags.as_short(),
                          name_index,
                          signature_index,
                          constantvalue_index);

    标记的是将常数给赋值了的操作

    今天先到这里,具体的解析在oop中的存储明天在说了

  • 相关阅读:
    Android学习总结——实现Home键功能
    Android学习总结——SQLite
    Android学习总结——文件储存
    Android学习总结——SharedPreferences
    Android学习总结——Content Provider
    Android学习总结——Service组件
    IDEA 创建和使用tomcat
    IDEA 图标介绍。 缓存和索引介绍、清理方法和Debug使用
    IDEA 常用快捷键
    IntelliJ IDEA常用设置(一)
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/14638025.html
Copyright © 2011-2022 走看看