Top


定義場所(file name)

hotspot/src/share/vm/classfile/classFileParser.cpp

名前(function name)

typeArrayHandle ClassFileParser::parse_fields(constantPoolHandle cp, bool is_interface,
                                              struct FieldAllocationCount *fac,
                                              objArrayHandle* fields_annotations, TRAPS) {

本体部(body)

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      ClassFileStream* cfs = stream();
      typeArrayHandle nullHandle;

  {- -------------------------------------------
  (1) まず, フィールドの個数を読み込む.
      ---------------------------------------- -}

      cfs->guarantee_more(2, CHECK_(nullHandle));  // length
      u2 length = cfs->get_u2_fast();

  {- -------------------------------------------
  (1) 次に, フィールド情報を格納するための typeArrayOop を作成する.
      typeArrayOop の大きさは, (上述の通り)「フィールド個数 * (u2 7個分)」.
      ---------------------------------------- -}

      // Tuples of shorts [access, name index, sig index, initial value index, byte offset, generic signature index]
      typeArrayOop new_fields = oopFactory::new_permanent_shortArray(length*instanceKlass::next_offset, CHECK_(nullHandle));
      typeArrayHandle fields(THREAD, new_fields);

  {- -------------------------------------------
  (1) 次に, フィールドの個数分だけループし, 以下のようにしてフィールド情報の読み込み処理を行う
      ---------------------------------------- -}

      int index = 0;
      typeArrayHandle field_annotations;
      for (int n = 0; n < length; n++) {
        cfs->guarantee_more(8, CHECK_(nullHandle));  // access_flags, name_index, descriptor_index, attributes_count

    {- -------------------------------------------
  (1.1) access_flags を読み込み, ClassFileParser::verify_legal_field_modifiers() で
        おかしな設定ではないかどうか確認する.
        ---------------------------------------- -}

        AccessFlags access_flags;
        jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
        verify_legal_field_modifiers(flags, is_interface, CHECK_(nullHandle));
        access_flags.set_flags(flags);

    {- -------------------------------------------
  (1.1) name_index を読み込み, その index 値が Constant Pool 内に収まっており,
        utf8_info を指していることを確認する.
        また, ClassFileParser::verify_legal_field_name() で
        フィールド名として妥当な utf8 文字列かどうかも確認する.
        ---------------------------------------- -}

        u2 name_index = cfs->get_u2_fast();
        int cp_size = cp->length();
        check_property(
          valid_cp_range(name_index, cp_size) && cp->tag_at(name_index).is_utf8(),
          "Invalid constant pool index %u for field name in class file %s",
          name_index, CHECK_(nullHandle));
        Symbol*  name = cp->symbol_at(name_index);
        verify_legal_field_name(name, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) signature_index (JVMS では descriptor_index) を読み込み,
        その index 値が Constant Pool 内に収まっており, utf8_info を指していることを確認する.
        また, ClassFileParser::verify_legal_field_signature() で
        フィールドの型情報(フィールド・ディスクリプタ)として妥当な utf8 文字列かどうかも確認する.
        ---------------------------------------- -}

        u2 signature_index = cfs->get_u2_fast();
        check_property(
          valid_cp_range(signature_index, cp_size) &&
            cp->tag_at(signature_index).is_utf8(),
          "Invalid constant pool index %u for field signature in class file %s",
          signature_index, CHECK_(nullHandle));
        Symbol*  sig = cp->symbol_at(signature_index);
        verify_legal_field_signature(name, sig, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) attributes_count を読み込んで attribute の個数を取得し, 
        ClassFileParser::parse_field_attributes() で, その個数分の attributes 情報を読み込む.
        ---------------------------------------- -}

        u2 constantvalue_index = 0;
        bool is_synthetic = false;
        u2 generic_signature_index = 0;
        bool is_static = access_flags.is_static();

        u2 attributes_count = cfs->get_u2_fast();
        if (attributes_count > 0) {
          parse_field_attributes(cp, attributes_count, is_static, signature_index,
                                 &constantvalue_index, &is_synthetic,
                                 &generic_signature_index, &field_annotations,
                                 CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) ClassFileParser::parse_field_attributes() の結果を調べ, 
        annotation や synthetic があった場合には処理を行う.
        ---------------------------------------- -}

    {- -------------------------------------------
  (1.1) * attributes 中に annotation があった場合: 
          引数として渡された objArrayHandle (以下の fields_annotations) に結果を書き込む.
          (fields_annotations が未確保であれば, oopFactory::new_system_objArray() による確保処理も行う)
        ---------------------------------------- -}

          if (field_annotations.not_null()) {
            if (fields_annotations->is_null()) {
              objArrayOop md = oopFactory::new_system_objArray(length, CHECK_(nullHandle));
              *fields_annotations = objArrayHandle(THREAD, md);
            }
            (*fields_annotations)->obj_at_put(n, field_annotations());
          }

    {- -------------------------------------------
  (1.1) * attributes 中に Synthetic attributes があった場合:
          access_flags に追加する.
        ---------------------------------------- -}

          if (is_synthetic) {
            access_flags.set_is_synthetic();
          }
        }

    {- -------------------------------------------
  (1.1) 次に, ここまでで読み込んだフィールド情報のいくつかを, 確保しておいた typeArrayOop (以下の "fields") に詰め込む
        ---------------------------------------- -}

        fields->short_at_put(index++, access_flags.as_short());
        fields->short_at_put(index++, name_index);
        fields->short_at_put(index++, signature_index);
        fields->short_at_put(index++, constantvalue_index);

    {- -------------------------------------------
  (1.1) 次に, フィールド・ディスクリプタ文字列を基に,
        フィールドの allocation type (FieldAllocationType) を決定する.

         <= 結果はビット数(および static フィールドかどうか)に応じて以下のようにまとめられる.
              bool, byte    => STATIC_BYTE   or NONSTATIC_BYTE
              char, short   => STATIC_SHORT  or NONSTATIC_SHORT
              int, float    => STATIC_WORD   or NONSTATIC_WORD
              long, double  => STATIC_DOUBLE or NONSTATIC_DOUBLE  (もしくは STATIC_ALIGNED_DOUBLE or NONSTATIC_ALIGNED_DOUBLE)
              object, array => STATIC_OOP    or NONSTATIC_OOP

         また, 合わせてこのフィールドの allocation type 情報を引数で渡された fac に加算していく.

         (なお, ConstantPoolOop::basic_type_for_signature_at() は,
          フィールド・ディスクリプタの先頭1文字だけを見て, 大まかな型を表す BasicType オブジェクトを返す関数)
        ---------------------------------------- -}

        // Remember how many oops we encountered and compute allocation type
        BasicType type = cp->basic_type_for_signature_at(signature_index);
        FieldAllocationType atype;
        if ( is_static ) {
          switch ( type ) {
            case  T_BOOLEAN:
            case  T_BYTE:
              fac->static_byte_count++;
              atype = STATIC_BYTE;
              break;
            case  T_LONG:
            case  T_DOUBLE:
              if (Universe::field_type_should_be_aligned(type)) {
                atype = STATIC_ALIGNED_DOUBLE;
              } else {
                atype = STATIC_DOUBLE;
              }
              fac->static_double_count++;
              break;
            case  T_CHAR:
            case  T_SHORT:
              fac->static_short_count++;
              atype = STATIC_SHORT;
              break;
            case  T_FLOAT:
            case  T_INT:
              fac->static_word_count++;
              atype = STATIC_WORD;
              break;
            case  T_ARRAY:
            case  T_OBJECT:
              fac->static_oop_count++;
              atype = STATIC_OOP;
              break;
            case  T_ADDRESS:
            case  T_VOID:
            default:
              assert(0, "bad field type");
          }
        } else {
          switch ( type ) {
            case  T_BOOLEAN:
            case  T_BYTE:
              fac->nonstatic_byte_count++;
              atype = NONSTATIC_BYTE;
              break;
            case  T_LONG:
            case  T_DOUBLE:
              if (Universe::field_type_should_be_aligned(type)) {
                atype = NONSTATIC_ALIGNED_DOUBLE;
              } else {
                atype = NONSTATIC_DOUBLE;
              }
              fac->nonstatic_double_count++;
              break;
            case  T_CHAR:
            case  T_SHORT:
              fac->nonstatic_short_count++;
              atype = NONSTATIC_SHORT;
              break;
            case  T_FLOAT:
            case  T_INT:
              fac->nonstatic_word_count++;
              atype = NONSTATIC_WORD;
              break;
            case  T_ARRAY:
            case  T_OBJECT:
              fac->nonstatic_oop_count++;
              atype = NONSTATIC_OOP;
              break;
            case  T_ADDRESS:
            case  T_VOID:
            default:
              assert(0, "bad field type");
          }
        }

    {- -------------------------------------------
  (1.1) 次に, 残りのフィールド情報を, 確保しておいた typeArrayOop (以下の "fields") に詰め込む.
        <= なお, low_offset, high_offset についてはまだ確定していないので,
           代わりに FieldAllocationType 情報 (以下の "atype") と適当な値 (以下の "0") を埋めている.
        ---------------------------------------- -}

        // The correct offset is computed later (all oop fields will be located together)
        // We temporarily store the allocation type in the offset field
        fields->short_at_put(index++, atype);
        fields->short_at_put(index++, 0);  // Clear out high word of byte offset
        fields->short_at_put(index++, generic_signature_index);

  {- -------------------------------------------
  (1) (ここまでで, ClassFileParser::parse_fields() 内のフィールド個数分のループは終了)
      ---------------------------------------- -}

      }

  {- -------------------------------------------
  (1) 次に, フィールドの定義が重複していないかどうかをチェックする. 
      (ただし _need_verify が立っていなければチェックしない)
      重複していたら ClassFormatError にする.
      ---------------------------------------- -}

      if (_need_verify && length > 1) {
        // Check duplicated fields
        ResourceMark rm(THREAD);
        NameSigHash** names_and_sigs = NEW_RESOURCE_ARRAY_IN_THREAD(
          THREAD, NameSigHash*, HASH_ROW_SIZE);
        initialize_hashtable(names_and_sigs);
        bool dup = false;
        {
          debug_only(No_Safepoint_Verifier nsv;)
          for (int i = 0; i < length*instanceKlass::next_offset; i += instanceKlass::next_offset) {
            int name_index = fields->ushort_at(i + instanceKlass::name_index_offset);
            Symbol* name = cp->symbol_at(name_index);
            int sig_index = fields->ushort_at(i + instanceKlass::signature_index_offset);
            Symbol* sig = cp->symbol_at(sig_index);
            // If no duplicates, add name/signature in hashtable names_and_sigs.
            if (!put_after_lookup(name, sig, names_and_sigs)) {
              dup = true;
              break;
            }
          }
        }
        if (dup) {
          classfile_parse_error("Duplicate field name&signature in class file %s",
                                CHECK_(nullHandle));
        }
      }

  {- -------------------------------------------
  (1) パース結果をリターンする
      ---------------------------------------- -}

      return fields;
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.