Top


定義場所(file name)

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

説明(description)

コメントによると, フットプリント削減のために methodOop 内にデータを詰め込んだ(データ構造をinline化した)(?)ため, method に関する情報を全部パースしないと methodOop のサイズが確定しない. そのため, ClassFileParser::parse_method() の処理も, メソッドに関する全ての部分の処理が全部入ってきていて「かなり見づらい」(big and clunky), とのこと.

(<= 関数でまとめるとかはできないもんだろうか. 難しいと書いてはあるが理由がいまいちわからない... #TODO)

なお, 結果は (返り値「だけ」ではなく) 引数で渡されたポインタにも書き込まれて返される.(#TODO) それぞれの引数に書き込まれる値は以下の通り.

#define MAX_ARGS_SIZE 255
#define MAX_CODE_SIZE 65535
#define INITIAL_MAX_LVT_NUMBER 256

// Note: the parse_method below is big and clunky because all parsing of the code and exceptions
// attribute is inlined. This is curbersome to avoid since we inline most of the parts in the
// methodOop to save footprint, so we only know the size of the resulting methodOop when the
// entire method attribute is parsed.
//
// The promoted_flags parameter is used to pass relevant access_flags
// from the method back up to the containing klass. These flag values
// are added to klass's access_flags.

名前(function name)

methodHandle ClassFileParser::parse_method(constantPoolHandle cp, bool is_interface,
                                           AccessFlags *promoted_flags,
                                           typeArrayHandle* method_annotations,
                                           typeArrayHandle* method_parameter_annotations,
                                           typeArrayHandle* method_default_annotations,
                                           TRAPS) {

本体部(body)

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

      ClassFileStream* cfs = stream();
      methodHandle nullHandle;
      ResourceMark rm(THREAD);

  {- -------------------------------------------
  (1) まず, method_info 中の固定長のヘッダ部分を読み込み, 以下のように値の確認を行う 
      (access_flags, name_index, descriptor_index, attributes_count).
      ---------------------------------------- -}

      // Parse fixed parts
      cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count

    {- -------------------------------------------
  (1.1) flags (JVMS では access_flags) を読み込む
        ---------------------------------------- -}

      int flags = cfs->get_u2_fast();

    {- -------------------------------------------
  (1.1) name_index を読み込み, その index 値が Constant Pool 内に収まっており,
        utf8_info を指していることを確認する.
        また, ClassFileParser::verify_legal_method_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(),
        "Illegal constant pool index %u for method name in class file %s",
        name_index, CHECK_(nullHandle));
      Symbol*  name = cp->symbol_at(name_index);
      verify_legal_method_name(name, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) signature_index (JVMS では descriptor_index) を読み込み,
        その index 値が Constant Pool 内に収まっており, utf8_info を指していることを確認する.
        ---------------------------------------- -}

      u2 signature_index = cfs->get_u2_fast();
      guarantee_property(
        valid_cp_range(signature_index, cp_size) &&
          cp->tag_at(signature_index).is_utf8(),
        "Illegal constant pool index %u for method signature in class file %s",
        signature_index, CHECK_(nullHandle));
      Symbol*  signature = cp->symbol_at(signature_index);

    {- -------------------------------------------
  (1.1) access_flags については, JVMS 4.6 に従い, <clinit> であれば無視している.
           ("Class and interface initialization methods (§2.9) are called
           implicitly by the Java virtual machine. The value of their
           access_flags item is ignored except for the setting of the ACC_STRICT flag.")
        <clinit> でなければ, ClassFileParser::verify_legal_method_modifiers() で
        おかしな設定ではないかどうか確認する.
        ---------------------------------------- -}

      AccessFlags access_flags;
      if (name == vmSymbols::class_initializer_name()) {
        // We ignore the other access flags for a valid class initializer.
        // (JVM Spec 2nd ed., chapter 4.6)
        if (_major_version < 51) { // backward compatibility
          flags = JVM_ACC_STATIC;
        } else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
          flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
        }
      } else {
        verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
      }

    {- -------------------------------------------
  (1.1) (_need_verify が立っていれば, signature_index が指す先の文字列について
         ClassFileParser::verify_legal_method_signature() で
         メソッドの型情報(メソッド・ディスクリプタ)として妥当な utf8 文字列かどうかも確認する.
         また, メソッドの引数が 255 個(MAX_ARGS_SIZE)以下かどうかを確認する.)
        ---------------------------------------- -}

      int args_size = -1;  // only used when _need_verify is true
      if (_need_verify) {
        args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) +
                     verify_legal_method_signature(name, signature, CHECK_(nullHandle));
        if (args_size > MAX_ARGS_SIZE) {
          classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle));
        }
      }

      access_flags.set_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);

  {- -------------------------------------------
  (1) (以下は メソッドの attributes 情報の読み込み処理.
       フィールドのパース処理と違って, この処理が別関数ではなく ClassFileParser::parse_method() 内部に展開されており, 読みづらい)
      ---------------------------------------- -}

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

      // Default values for code and exceptions attribute elements
      u2 max_stack = 0;
      u2 max_locals = 0;
      u4 code_length = 0;
      u1* code_start = 0;
      u2 exception_table_length = 0;
      typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array());
      u2 checked_exceptions_length = 0;
      u2* checked_exceptions_start = NULL;
      CompressedLineNumberWriteStream* linenumber_table = NULL;
      int linenumber_table_length = 0;
      int total_lvt_length = 0;
      u2 lvt_cnt = 0;
      u2 lvtt_cnt = 0;
      bool lvt_allocated = false;
      u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER;
      u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER;
      u2* localvariable_table_length;
      u2** localvariable_table_start;
      u2* localvariable_type_table_length;
      u2** localvariable_type_table_start;
      bool parsed_code_attribute = false;
      bool parsed_checked_exceptions_attribute = false;
      bool parsed_stackmap_attribute = false;
      // stackmap attribute - JDK1.5
      typeArrayHandle stackmap_data;
      u2 generic_signature_index = 0;
      u1* runtime_visible_annotations = NULL;
      int runtime_visible_annotations_length = 0;
      u1* runtime_invisible_annotations = NULL;
      int runtime_invisible_annotations_length = 0;
      u1* runtime_visible_parameter_annotations = NULL;
      int runtime_visible_parameter_annotations_length = 0;
      u1* runtime_invisible_parameter_annotations = NULL;
      int runtime_invisible_parameter_annotations_length = 0;
      u1* annotation_default = NULL;
      int annotation_default_length = 0;

  {- -------------------------------------------
  (1) attribute の個数分だけループし, 以下のように値の読み込み処理を行う.
      ---------------------------------------- -}

      // Parse code and exceptions attribute
      u2 method_attributes_count = cfs->get_u2_fast();
      while (method_attributes_count--) {

    {- -------------------------------------------
  (1.1) attribute_name_index と attribute_length を読み込む.
        attribute_name_index については, その index 値が Constant Pool 内に収まっており, 
        utf8_info を指していることを確認する.
        ---------------------------------------- -}

        cfs->guarantee_more(6, CHECK_(nullHandle));  // method_attribute_name_index, method_attribute_length
        u2 method_attribute_name_index = cfs->get_u2_fast();
        u4 method_attribute_length = cfs->get_u4_fast();
        check_property(
          valid_cp_range(method_attribute_name_index, cp_size) &&
            cp->tag_at(method_attribute_name_index).is_utf8(),
          "Invalid method attribute name index %u in class file %s",
          method_attribute_name_index, CHECK_(nullHandle));

        Symbol* method_attribute_name = cp->symbol_at(method_attribute_name_index);

    {- -------------------------------------------
  (1.1) 以下, 読み込んだ attribute_name に応じて, 適切に読み込み処理&内容の確認処理を行う.
        ---------------------------------------- -}

        if (method_attribute_name == vmSymbols::tag_code()) {

    {- -------------------------------------------
  (1.1) * Code attribute の場合, (処理が長いので, このケースだけ小分けにして説明)
        ---------------------------------------- -}

          // Parse Code attribute

      {- -------------------------------------------
  (1.1.1) * (_need_verify が立っていれば), access_flags 中の native や abstract が立っていないことを確認
          ---------------------------------------- -}

          if (_need_verify) {
            guarantee_property(!access_flags.is_native() && !access_flags.is_abstract(),
                            "Code attribute in native or abstract methods in class file %s",
                             CHECK_(nullHandle));
          }

      {- -------------------------------------------
  (1.1.1) * 既に, Code attribute を読み込んでいないかどうかを確認 (重複していたら ClassFormatError)
          ---------------------------------------- -}

          if (parsed_code_attribute) {
            classfile_parse_error("Multiple Code attributes in class file %s", CHECK_(nullHandle));
          }
          parsed_code_attribute = true;

      {- -------------------------------------------
  (1.1.1) * Stack size, locals size, および code size を読み込む.
            (_need_verify が立っていれば), args_size <= max_locals であることと, 
            0 < code_length <= MAX_CODE_SIZE であることを確認.                            
          ---------------------------------------- -}

          // Stack size, locals size, and code size
          if (_major_version == 45 && _minor_version <= 2) {
            cfs->guarantee_more(4, CHECK_(nullHandle));
            max_stack = cfs->get_u1_fast();
            max_locals = cfs->get_u1_fast();
            code_length = cfs->get_u2_fast();
          } else {
            cfs->guarantee_more(8, CHECK_(nullHandle));
            max_stack = cfs->get_u2_fast();
            max_locals = cfs->get_u2_fast();
            code_length = cfs->get_u4_fast();
          }
          if (_need_verify) {
            guarantee_property(args_size <= max_locals,
                               "Arguments can't fit into locals in class file %s", CHECK_(nullHandle));
            guarantee_property(code_length > 0 && code_length <= MAX_CODE_SIZE,
                               "Invalid method Code length %u in class file %s",
                               code_length, CHECK_(nullHandle));
          }

      {- -------------------------------------------
  (1.1.1) * 次に, byte code の先頭のアドレスを取得する. 
             (get_u1_buffer() は現在のポインタ値を返す. 現在のポインタの指す1byteを返す get_u1_fast() とは違うので注意)
          ---------------------------------------- -}

          // Code pointer
          code_start = cfs->get_u1_buffer();
          assert(code_start != NULL, "null code start");

      {- -------------------------------------------
  (1.1.1) * byte code 自体はとりあえずスキップして次に進む
          ---------------------------------------- -}

          cfs->guarantee_more(code_length, CHECK_(nullHandle));
          cfs->skip_u1_fast(code_length);

      {- -------------------------------------------
  (1.1.1) * 次に, exception_table_length を読み込み, 
            exception_table_length が 0 より大きければ
            ClassFileParser::parse_exception_table() で exception_table を読み込む.
          ---------------------------------------- -}

          // Exception handler table
          cfs->guarantee_more(2, CHECK_(nullHandle));  // exception_table_length
          exception_table_length = cfs->get_u2_fast();
          if (exception_table_length > 0) {
            exception_handlers =
                  parse_exception_table(code_length, exception_table_length, cp, CHECK_(nullHandle));
          }

      {- -------------------------------------------
  (1.1.1) * 次に, Code attribute に付属する attribute を全て読み込む. (#TODO)
          ---------------------------------------- -}

          // Parse additional attributes in code attribute
          cfs->guarantee_more(2, CHECK_(nullHandle));  // code_attributes_count
          u2 code_attributes_count = cfs->get_u2_fast();

          unsigned int calculated_attribute_length = 0;

          if (_major_version > 45 || (_major_version == 45 && _minor_version > 2)) {
            calculated_attribute_length =
                sizeof(max_stack) + sizeof(max_locals) + sizeof(code_length);
          } else {
            // max_stack, locals and length are smaller in pre-version 45.2 classes
            calculated_attribute_length = sizeof(u1) + sizeof(u1) + sizeof(u2);
          }
          calculated_attribute_length +=
            code_length +
            sizeof(exception_table_length) +
            sizeof(code_attributes_count) +
            exception_table_length *
                ( sizeof(u2) +   // start_pc
                  sizeof(u2) +   // end_pc
                  sizeof(u2) +   // handler_pc
                  sizeof(u2) );  // catch_type_index

          while (code_attributes_count--) {
            cfs->guarantee_more(6, CHECK_(nullHandle));  // code_attribute_name_index, code_attribute_length
            u2 code_attribute_name_index = cfs->get_u2_fast();
            u4 code_attribute_length = cfs->get_u4_fast();
            calculated_attribute_length += code_attribute_length +
                                           sizeof(code_attribute_name_index) +
                                           sizeof(code_attribute_length);
            check_property(valid_cp_range(code_attribute_name_index, cp_size) &&
                           cp->tag_at(code_attribute_name_index).is_utf8(),
                           "Invalid code attribute name index %u in class file %s",
                           code_attribute_name_index,
                           CHECK_(nullHandle));
            if (LoadLineNumberTables &&
                cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
              // Parse and compress line number table
              parse_linenumber_table(code_attribute_length, code_length,
                &linenumber_table, CHECK_(nullHandle));

            } else if (LoadLocalVariableTables &&
                       cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
              // Parse local variable table
              if (!lvt_allocated) {
                localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2,  INITIAL_MAX_LVT_NUMBER);
                localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
                localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2,  INITIAL_MAX_LVT_NUMBER);
                localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
                lvt_allocated = true;
              }
              if (lvt_cnt == max_lvt_cnt) {
                max_lvt_cnt <<= 1;
                REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt);
                REALLOC_RESOURCE_ARRAY(u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
              }
              localvariable_table_start[lvt_cnt] =
                parse_localvariable_table(code_length,
                                          max_locals,
                                          code_attribute_length,
                                          cp,
                                          &localvariable_table_length[lvt_cnt],
                                          false,    // is not LVTT
                                          CHECK_(nullHandle));
              total_lvt_length += localvariable_table_length[lvt_cnt];
              lvt_cnt++;
            } else if (LoadLocalVariableTypeTables &&
                       _major_version >= JAVA_1_5_VERSION &&
                       cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
              if (!lvt_allocated) {
                localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2,  INITIAL_MAX_LVT_NUMBER);
                localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
                localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2,  INITIAL_MAX_LVT_NUMBER);
                localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
                lvt_allocated = true;
              }
              // Parse local variable type table
              if (lvtt_cnt == max_lvtt_cnt) {
                max_lvtt_cnt <<= 1;
                REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt);
                REALLOC_RESOURCE_ARRAY(u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
              }
              localvariable_type_table_start[lvtt_cnt] =
                parse_localvariable_table(code_length,
                                          max_locals,
                                          code_attribute_length,
                                          cp,
                                          &localvariable_type_table_length[lvtt_cnt],
                                          true,     // is LVTT
                                          CHECK_(nullHandle));
              lvtt_cnt++;
            } else if (UseSplitVerifier &&
                       _major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION &&
                       cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
              // Stack map is only needed by the new verifier in JDK1.5.
              if (parsed_stackmap_attribute) {
                classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle));
              }
              typeArrayOop sm =
                parse_stackmap_table(code_attribute_length, CHECK_(nullHandle));
              stackmap_data = typeArrayHandle(THREAD, sm);
              parsed_stackmap_attribute = true;
            } else {
              // Skip unknown attributes
              cfs->skip_u1(code_attribute_length, CHECK_(nullHandle));
            }
          }
          // check method attribute length
          if (_need_verify) {
            guarantee_property(method_attribute_length == calculated_attribute_length,
                               "Code segment has wrong length in class file %s", CHECK_(nullHandle));
          }

    {- -------------------------------------------
  (1.1) (ここまでが Code attribute の場合の処理)
        ---------------------------------------- -}

    {- -------------------------------------------
  (1.1) * Exceptions attribute の場合は, 1つのメソッドに複数の Exceptions attribute が指定されてはいけない.

          以上のチェックが終わったら, ClassFileParser::parse_checked_exceptions() で
          Exceptions attribute を読み込む.
        ---------------------------------------- -}

        } else if (method_attribute_name == vmSymbols::tag_exceptions()) {
          // Parse Exceptions attribute
          if (parsed_checked_exceptions_attribute) {
            classfile_parse_error("Multiple Exceptions attributes in class file %s", CHECK_(nullHandle));
          }
          parsed_checked_exceptions_attribute = true;
          checked_exceptions_start =
                parse_checked_exceptions(&checked_exceptions_length,
                                         method_attribute_length,
                                         cp, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) * Synthetic attribute の場合は, attribute_length が 0 でないといけない.
          (Synthetic attribute には他に情報は無いので単にこれだけ)

          以上のチェックが終わったら, 読み込んだ access_flags 情報にこの情報を足し込む.
        ---------------------------------------- -}

        } else if (method_attribute_name == vmSymbols::tag_synthetic()) {
          if (method_attribute_length != 0) {
            classfile_parse_error(
              "Invalid Synthetic method attribute length %u in class file %s",
              method_attribute_length, CHECK_(nullHandle));
          }
          // Should we check that there hasn't already been a synthetic attribute?
          access_flags.set_is_synthetic();

    {- -------------------------------------------
  (1.1) * Deprecated attribute の場合は, attribute_length が 0 でないといけない.
          (Deprecated attribute には他に情報は無いので単にこれだけ)

          (Deprecated attribute については, 呼び出し元には何の情報も返されない)
        ---------------------------------------- -}

        } else if (method_attribute_name == vmSymbols::tag_deprecated()) { // 4276120
          if (method_attribute_length != 0) {
            classfile_parse_error(
              "Invalid Deprecated method attribute length %u in class file %s",
              method_attribute_length, CHECK_(nullHandle));
          }

    {- -------------------------------------------
  (1.1) * バージョンが Java 5 以降であれば, Java 5 で追加されたアノテーションの処理も行う. (#TODO)
        ---------------------------------------- -}

        } else if (_major_version >= JAVA_1_5_VERSION) {
          if (method_attribute_name == vmSymbols::tag_signature()) {
            if (method_attribute_length != 2) {
              classfile_parse_error(
                "Invalid Signature attribute length %u in class file %s",
                method_attribute_length, CHECK_(nullHandle));
            }
            cfs->guarantee_more(2, CHECK_(nullHandle));  // generic_signature_index
            generic_signature_index = cfs->get_u2_fast();
          } else if (method_attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
            runtime_visible_annotations_length = method_attribute_length;
            runtime_visible_annotations = cfs->get_u1_buffer();
            assert(runtime_visible_annotations != NULL, "null visible annotations");
            cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
          } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
            runtime_invisible_annotations_length = method_attribute_length;
            runtime_invisible_annotations = cfs->get_u1_buffer();
            assert(runtime_invisible_annotations != NULL, "null invisible annotations");
            cfs->skip_u1(runtime_invisible_annotations_length, CHECK_(nullHandle));
          } else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
            runtime_visible_parameter_annotations_length = method_attribute_length;
            runtime_visible_parameter_annotations = cfs->get_u1_buffer();
            assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations");
            cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_(nullHandle));
          } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
            runtime_invisible_parameter_annotations_length = method_attribute_length;
            runtime_invisible_parameter_annotations = cfs->get_u1_buffer();
            assert(runtime_invisible_parameter_annotations != NULL, "null invisible parameter annotations");
            cfs->skip_u1(runtime_invisible_parameter_annotations_length, CHECK_(nullHandle));
          } else if (method_attribute_name == vmSymbols::tag_annotation_default()) {
            annotation_default_length = method_attribute_length;
            annotation_default = cfs->get_u1_buffer();
            assert(annotation_default != NULL, "null annotation default");
            cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) もし認識できない attribute であれば, 単に読み飛ばすだけ.
        (なお 2つあるのは, _major_version >= JAVA_1_5_VERSION の場合とそうでない場合に対応. どちらにせよ読み飛ばすだけだけど)
        ---------------------------------------- -}

          } else {
            // Skip unknown attributes
            cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
          }
        } else {
          // Skip unknown attributes
          cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
        }
      }

  {- -------------------------------------------
  (1) ?? #TODO
      ---------------------------------------- -}

      if (linenumber_table != NULL) {
        linenumber_table->write_terminator();
        linenumber_table_length = linenumber_table->position();
      }

  {- -------------------------------------------
  (1) もしこの段階で (native や abstract ではないのに) Code attribute が1つもなければエラー
      ---------------------------------------- -}

      // Make sure there's at least one Code attribute in non-native/non-abstract method
      if (_need_verify) {
        guarantee_property(access_flags.is_native() || access_flags.is_abstract() || parsed_code_attribute,
                          "Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle));
      }

  {- -------------------------------------------
  (1) 次に, ここまでで読み込んだデータから methodOop を作成する.
      ---------------------------------------- -}

      // All sizing information for a methodOop is finally available, now create it
      methodOop m_oop  = oopFactory::new_method(code_length, access_flags, linenumber_table_length,
                                                total_lvt_length, checked_exceptions_length,
                                                oopDesc::IsSafeConc, CHECK_(nullHandle));
      methodHandle m (THREAD, m_oop);

  {- -------------------------------------------
  (1) (JMM のフック点)
      ---------------------------------------- -}

      ClassLoadingService::add_class_method_size(m_oop->size()*HeapWordSize);

  {- -------------------------------------------
  (1) 次に, 作成した methodOop の中身を埋めていく.
      まずは固定長の部分から埋めていき,
      codes や line number table 等へと続き,
      そして最後に local variable table (LVT) で完了.  (詳細は見てない #TODO)
      ---------------------------------------- -}

      // Fill in information from fixed part (access_flags already set)
      m->set_constants(cp());
      m->set_name_index(name_index);
      m->set_signature_index(signature_index);
      m->set_generic_signature_index(generic_signature_index);
    #ifdef CC_INTERP
      // hmm is there a gc issue here??
      ResultTypeFinder rtf(cp->symbol_at(signature_index));
      m->set_result_index(rtf.type());
    #endif

      if (args_size >= 0) {
        m->set_size_of_parameters(args_size);
      } else {
        m->compute_size_of_parameters(THREAD);
      }
    #ifdef ASSERT
      if (args_size >= 0) {
        m->compute_size_of_parameters(THREAD);
        assert(args_size == m->size_of_parameters(), "");
      }
    #endif

      // Fill in code attribute information
      m->set_max_stack(max_stack);
      m->set_max_locals(max_locals);
      m->constMethod()->set_stackmap_data(stackmap_data());

      /**
       * The exception_table field is the flag used to indicate
       * that the methodOop and it's associated constMethodOop are partially
       * initialized and thus are exempt from pre/post GC verification.  Once
       * the field is set, the oops are considered fully initialized so make
       * sure that the oops can pass verification when this field is set.
       */
      m->set_exception_table(exception_handlers());

      // Copy byte codes
      m->set_code(code_start);

      // Copy line number table
      if (linenumber_table != NULL) {
        memcpy(m->compressed_linenumber_table(),
               linenumber_table->buffer(), linenumber_table_length);
      }

      // Copy checked exceptions
      if (checked_exceptions_length > 0) {
        int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
        copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size);
      }

      /* Copy class file LVT's/LVTT's into the HotSpot internal LVT.
       *
       * Rules for LVT's and LVTT's are:
       *   - There can be any number of LVT's and LVTT's.
       *   - If there are n LVT's, it is the same as if there was just
       *     one LVT containing all the entries from the n LVT's.
       *   - There may be no more than one LVT entry per local variable.
       *     Two LVT entries are 'equal' if these fields are the same:
       *        start_pc, length, name, slot
       *   - There may be no more than one LVTT entry per each LVT entry.
       *     Each LVTT entry has to match some LVT entry.
       *   - HotSpot internal LVT keeps natural ordering of class file LVT entries.
       */
      if (total_lvt_length > 0) {
        int tbl_no, idx;

        promoted_flags->set_has_localvariable_table();

        LVT_Hash** lvt_Hash = NEW_RESOURCE_ARRAY(LVT_Hash*, HASH_ROW_SIZE);
        initialize_hashtable(lvt_Hash);

        // To fill LocalVariableTable in
        Classfile_LVT_Element*  cf_lvt;
        LocalVariableTableElement* lvt = m->localvariable_table_start();

        for (tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) {
          cf_lvt = (Classfile_LVT_Element *) localvariable_table_start[tbl_no];
          for (idx = 0; idx < localvariable_table_length[tbl_no]; idx++, lvt++) {
            copy_lvt_element(&cf_lvt[idx], lvt);
            // If no duplicates, add LVT elem in hashtable lvt_Hash.
            if (LVT_put_after_lookup(lvt, lvt_Hash) == false
              && _need_verify
              && _major_version >= JAVA_1_5_VERSION ) {
              clear_hashtable(lvt_Hash);
              classfile_parse_error("Duplicated LocalVariableTable attribute "
                                    "entry for '%s' in class file %s",
                                     cp->symbol_at(lvt->name_cp_index)->as_utf8(),
                                     CHECK_(nullHandle));
            }
          }
        }

        // To merge LocalVariableTable and LocalVariableTypeTable
        Classfile_LVT_Element* cf_lvtt;
        LocalVariableTableElement lvtt_elem;

        for (tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) {
          cf_lvtt = (Classfile_LVT_Element *) localvariable_type_table_start[tbl_no];
          for (idx = 0; idx < localvariable_type_table_length[tbl_no]; idx++) {
            copy_lvt_element(&cf_lvtt[idx], &lvtt_elem);
            int index = hash(&lvtt_elem);
            LVT_Hash* entry = LVT_lookup(&lvtt_elem, index, lvt_Hash);
            if (entry == NULL) {
              if (_need_verify) {
                clear_hashtable(lvt_Hash);
                classfile_parse_error("LVTT entry for '%s' in class file %s "
                                      "does not match any LVT entry",
                                       cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(),
                                       CHECK_(nullHandle));
              }
            } else if (entry->_elem->signature_cp_index != 0 && _need_verify) {
              clear_hashtable(lvt_Hash);
              classfile_parse_error("Duplicated LocalVariableTypeTable attribute "
                                    "entry for '%s' in class file %s",
                                     cp->symbol_at(lvtt_elem.name_cp_index)->as_utf8(),
                                     CHECK_(nullHandle));
            } else {
              // to add generic signatures into LocalVariableTable
              entry->_elem->signature_cp_index = lvtt_elem.descriptor_cp_index;
            }
          }
        }
        clear_hashtable(lvt_Hash);
      }

  {- -------------------------------------------
  (1) 次に, アノテーション情報を引数で渡されたポインタに格納する.
      ---------------------------------------- -}

      *method_annotations = assemble_annotations(runtime_visible_annotations,
                                                 runtime_visible_annotations_length,
                                                 runtime_invisible_annotations,
                                                 runtime_invisible_annotations_length,
                                                 CHECK_(nullHandle));
      *method_parameter_annotations = assemble_annotations(runtime_visible_parameter_annotations,
                                                           runtime_visible_parameter_annotations_length,
                                                           runtime_invisible_parameter_annotations,
                                                           runtime_invisible_parameter_annotations_length,
                                                           CHECK_(nullHandle));
      *method_default_annotations = assemble_annotations(annotation_default,
                                                         annotation_default_length,
                                                         NULL,
                                                         0,
                                                         CHECK_(nullHandle));

  {- -------------------------------------------
  (1) finalizer や initializer であればフラグを立てる.
      (このフラグは何のために使われている? #TODO)
      ---------------------------------------- -}

      if (name == vmSymbols::finalize_method_name() &&
          signature == vmSymbols::void_method_signature()) {
        if (m->is_empty_method()) {
          _has_empty_finalizer = true;
        } else {
          _has_finalizer = true;
        }
      }
      if (name == vmSymbols::object_initializer_name() &&
          signature == vmSymbols::void_method_signature() &&
          m->is_vanilla_constructor()) {
        _has_vanilla_constructor = true;
      }

  {- -------------------------------------------
  (1) ?? #TODO
      ---------------------------------------- -}

      if (EnableInvokeDynamic && (m->is_method_handle_invoke() ||
                                  m->is_method_handle_adapter())) {
        THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
                   "Method handle invokers must be defined internally to the VM", nullHandle);
      }

  {- -------------------------------------------
  (1) 最後に, パース結果の methodOop をリターン.
      ---------------------------------------- -}

      return m;
    }

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