Top


定義場所(file name)

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

名前(function name)

instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
                                                    Handle class_loader,
                                                    Handle protection_domain,
                                                    KlassHandle host_klass,
                                                    GrowableArray<Handle>* cp_patches,
                                                    TempNewSymbol& parsed_name,
                                                    bool verify,
                                                    TRAPS) {

本体部(body)

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

      // So that JVMTI can cache class file in the state before retransformable agents
      // have modified it
      unsigned char *cached_class_file_bytes = NULL;
      jint cached_class_file_length;

  {- -------------------------------------------
  (1) クラスファイルを読むための ClassFileStream を作成.
      ---------------------------------------- -}

      ClassFileStream* cfs = stream();

  {- -------------------------------------------
  (1) PerfClassTraceTime のインスタンスを作成し, クラスローディングにかかった時間の計測を開始する
      ---------------------------------------- -}

      // Timing
      assert(THREAD->is_Java_thread(), "must be a JavaThread");
      JavaThread* jt = (JavaThread*) THREAD;

      PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(),
                                ClassLoader::perf_class_parse_selftime(),
                                NULL,
                                jt->get_thread_stat()->perf_recursion_counts_addr(),
                                jt->get_thread_stat()->perf_timers_addr(),
                                PerfClassTraceTime::PARSE_CLASS);

  {- -------------------------------------------
  (1) (フィールドの初期化)
      ---------------------------------------- -}

      _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
      _max_bootstrap_specifier_index = -1;

  {- -------------------------------------------
  (1) (JVMTI のフック点)
      (なお, JVMTI agent によってクラスファイルの変更が行われた場合は, ClassFileStream をそちらに切り替える)
      ---------------------------------------- -}

      if (JvmtiExport::should_post_class_file_load_hook()) {
        unsigned char* ptr = cfs->buffer();
        unsigned char* end_ptr = cfs->buffer() + cfs->length();

        JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain,
                                               &ptr, &end_ptr,
                                               &cached_class_file_bytes,
                                               &cached_class_file_length);

        if (ptr != cfs->buffer()) {
          // JVMTI agent has modified class file data.
          // Set new class file stream using JVMTI agent modified
          // class file data.
          cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
          set_stream(cfs);
        }
      }

  {- -------------------------------------------
  (1) (フィールドの初期化)
      ---------------------------------------- -}

      _host_klass = host_klass;
      _cp_patches = cp_patches;

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

      instanceKlassHandle nullHandle;

  {- -------------------------------------------
  (1) 対象のクラスに対する verify が必要かどうかを確認しておく.
      (デフォルトでは bootstrap class loader がロードしたものは verify は不要としている. -Xverify:all/none で設定を変更可能.)
      ---------------------------------------- -}

      // Figure out whether we can skip format checking (matching classic VM behavior)
      _need_verify = Verifier::should_verify_for(class_loader(), verify);

      // Set the verify flag in stream
      cfs->set_verify(_need_verify);

  {- -------------------------------------------
  (1) エラーメッセージの出力時に備えてクラス名を記憶しておく
      ---------------------------------------- -}

      // Save the class file name for easier error message printing.
      _class_name = (name != NULL) ? name : vmSymbols::unknown_class_name();

  {- -------------------------------------------
  (1) まず, magic number や version number を読み込み, 
      ClassFileParser::is_supported_version() で確認を行う.
      (version number が合わなければ UnsupportedClassVersionError).
      ---------------------------------------- -}

      cfs->guarantee_more(8, CHECK_(nullHandle));  // magic, major, minor
      // Magic value
      u4 magic = cfs->get_u4_fast();
      guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
                         "Incompatible magic value %u in class file %s",
                         magic, CHECK_(nullHandle));

      // Version numbers
      u2 minor_version = cfs->get_u2_fast();
      u2 major_version = cfs->get_u2_fast();

      // Check version numbers - we check this even with verifier off
      if (!is_supported_version(major_version, minor_version)) {
        if (name == NULL) {
          Exceptions::fthrow(
            THREAD_AND_LOCATION,
            vmSymbols::java_lang_UnsupportedClassVersionError(),
            "Unsupported major.minor version %u.%u",
            major_version,
            minor_version);
        } else {
          ResourceMark rm(THREAD);
          Exceptions::fthrow(
            THREAD_AND_LOCATION,
            vmSymbols::java_lang_UnsupportedClassVersionError(),
            "%s : Unsupported major.minor version %u.%u",
            name->as_C_string(),
            major_version,
            minor_version);
        }
        return nullHandle;
      }

  {- -------------------------------------------
  (1) (フィールドの初期化)
      (version number 番号情報を記録しておく)
      ---------------------------------------- -}

      _major_version = major_version;
      _minor_version = minor_version;


  {- -------------------------------------------
  (1) 「いくつかの broken な 1.1 API を 1.2 でも動かすために, verify を relaxed させるべきかどうか」を調べる
      ---------------------------------------- -}

      // Check if verification needs to be relaxed for this class file
      // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
      _relax_verify = Verifier::relax_verify_for(class_loader());

  {- -------------------------------------------
  (1) ClassFileParser::parse_constant_pool() を呼んで, コンスタントプール情報を読み込む.
      ---------------------------------------- -}

      // Constant pool
      constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
      ConstantPoolCleaner error_handler(cp); // set constant pool to be cleaned up.

      int cp_size = cp->length();

      cfs->guarantee_more(8, CHECK_(nullHandle));  // flags, this_class, super_class, infs_len

  {- -------------------------------------------
  (1) 次に, access_flags の値を読み込む.

      (<= Java 6 より前のバージョンでは, JVM_ACC_INTERFACE が立っているのに JVM_ACC_ABSTRACT が立っていなくてもいい??
      古い Java 仮想マシン仕様でも立っていないと駄目だと書いているが... (#TODO))
      ---------------------------------------- -}

      // Access flags
      AccessFlags access_flags;
      jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;

      if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
        // Set abstract bit for old class files for backward compatibility
        flags |= JVM_ACC_ABSTRACT;
      }
      verify_legal_class_modifiers(flags, CHECK_(nullHandle));
      access_flags.set_flags(flags);

  {- -------------------------------------------
  (1) 次に, this_class を読み込み, 以下のようにチェックを行う.
      ---------------------------------------- -}

      // This class and superclass
      instanceKlassHandle super_klass;
      u2 this_class_index = cfs->get_u2_fast();

    {- -------------------------------------------
  (1.1) this_class に入っていた index の値が, Constant Pool 内に収まっており,
        unresolved な klass を指していることを確認.
        ---------------------------------------- -}

      check_property(
        valid_cp_range(this_class_index, cp_size) &&
          cp->tag_at(this_class_index).is_unresolved_klass(),
        "Invalid this class index %u in constant pool in class file %s",
        this_class_index, CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) Constant Pool から this_class が指すクラス名を取得
        (取得した Symbol は reference count を増加させて解放されないようにしておく)
        ---------------------------------------- -}

      Symbol*  class_name  = cp->unresolved_klass_at(this_class_index);
      assert(class_name != NULL, "class_name can't be null");

      // It's important to set parsed_name *before* resolving the super class.
      // (it's used for cleanup by the caller if parsing fails)
      parsed_name = class_name;
      // parsed_name is returned and can be used if there's an error, so add to
      // its reference count.  Caller will decrement the refcount.
      parsed_name->increment_refcount();

    {- -------------------------------------------
  (1.1) 実際にクラスファイル中からクラス名が取得できたので, エラーメッセージ出力時用のクラス名を更新しておく.
        (この時点までは NULL の可能性があった)
        ---------------------------------------- -}

      // Update _class_name which could be null previously to be class_name
      _class_name = class_name;

    {- -------------------------------------------
  (1.1) verify の必要があれば, this_class が array type になっていないことを確認.
        ---------------------------------------- -}

      // Don't need to check whether this class name is legal or not.
      // It has been checked when constant pool is parsed.
      // However, make sure it is not an array type.
      if (_need_verify) {
        guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
                           "Bad class name in class file %s",
                           CHECK_(nullHandle));
      }

    {- -------------------------------------------
  (1.1) (変数宣言など)
        (以下の block の末尾で, パース処理に使っていた handle は全て HandleMark によって回収されることになる.
         ただし, this_klass に関する handle は返り値として返す必要があるので,
         HandleMark 外で宣言した preserve_this_klass に退避させて HandleMark に回収されないようにしている.)
        ---------------------------------------- -}

      klassOop preserve_this_klass;   // for storing result across HandleMark

      // release all handles when parsing is done
      { HandleMark hm(THREAD);

    {- -------------------------------------------
  (1.1) もし, this_class のクラス名が null だったり要求されていたクラス名と違っていたら
        NoClassDefFoundError を投げて, ここでリターン.
        ---------------------------------------- -}

        // Checks if name in class file matches requested name
        if (name != NULL && class_name != name) {
          ResourceMark rm(THREAD);
          Exceptions::fthrow(
            THREAD_AND_LOCATION,
            vmSymbols::java_lang_NoClassDefFoundError(),
            "%s (wrong name: %s)",
            name->as_C_string(),
            class_name->as_C_string()
          );
          return nullHandle;
        }

    {- -------------------------------------------
  (1.1) (トレース出力)
        ---------------------------------------- -}

        if (TraceClassLoadingPreorder) {
          tty->print("[Loading %s", name->as_klass_external_name());
          if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
          tty->print_cr("]");
        }

  {- -------------------------------------------
  (1) 次に, super_class を読み込み, 以下のようにチェックを行う.
      ---------------------------------------- -}

        u2 super_class_index = cfs->get_u2_fast();

    {- -------------------------------------------
  (1.1) super_class_index が 0 だった場合は, java_lang_Object かどうかを確認.
        ---------------------------------------- -}

        if (super_class_index == 0) {
          check_property(class_name == vmSymbols::java_lang_Object(),
                         "Invalid superclass index %u in class file %s",
                         super_class_index,
                         CHECK_(nullHandle));

    {- -------------------------------------------
  (1.1) super_class_index が 0 でなければ, その index 値が Constant Pool 内に収まっており,
        class を指していること, また array ではないことを確認.
        ---------------------------------------- -}

        } else {
          check_property(valid_cp_range(super_class_index, cp_size) &&
                         is_klass_reference(cp, super_class_index),
                         "Invalid superclass index %u in class file %s",
                         super_class_index,
                         CHECK_(nullHandle));
          // The class name should be legal because it is checked when parsing constant pool.
          // However, make sure it is not an array type.
          bool is_array = false;
          if (cp->tag_at(super_class_index).is_klass()) {
            super_klass = instanceKlassHandle(THREAD, cp->resolved_klass_at(super_class_index));
            if (_need_verify)
              is_array = super_klass->oop_is_array();
          } else if (_need_verify) {
            is_array = (cp->unresolved_klass_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
          }
          if (_need_verify) {
            guarantee_property(!is_array,
                              "Bad superclass name in class file %s", CHECK_(nullHandle));
          }
        }

  {- -------------------------------------------
  (1) 次に, 実装しているインターフェースの情報を以下のように読み込む (インターフェースの個数, 及び実際のインターフェース情報).
      ---------------------------------------- -}

        // Interfaces

    {- -------------------------------------------
  (1.1) まず, 実装したインターフェースの個数を読み込む.
        ---------------------------------------- -}

        u2 itfs_len = cfs->get_u2_fast();

    {- -------------------------------------------
  (1.1) 次に, ClassFileParser::parse_interfaces() で
        インターフェース情報(constant pool への index の配列)の読み込みと確認を行う.
        (なお, 読み込んだ結果は objArrayOop として保持する)
        ---------------------------------------- -}

        objArrayHandle local_interfaces;
        if (itfs_len == 0) {
          local_interfaces = objArrayHandle(THREAD, Universe::the_empty_system_obj_array());
        } else {
          local_interfaces = parse_interfaces(cp, itfs_len, class_loader, protection_domain, _class_name, CHECK_(nullHandle));
        }

  {- -------------------------------------------
  (1) 次に, フィールドの情報を読み込む (フィールドの個数, 及び実際のフィールド情報).
      (なお, ここで各フィールドに付属するアトリビュート情報も読み込む).
      ---------------------------------------- -}

        // Fields (offsets are filled in later)
        struct FieldAllocationCount fac = {0,0,0,0,0,0,0,0,0,0};
        objArrayHandle fields_annotations;
        typeArrayHandle fields = parse_fields(cp, access_flags.is_interface(), &fac, &fields_annotations, CHECK_(nullHandle));

  {- -------------------------------------------
  (1) 次に, メソッドの情報を読み込む (メソッドの個数, 及び実際のメソッド情報).
      (なお, ここで各メソッドに付属するアトリビュート情報も読み込む).
      ---------------------------------------- -}

        // Methods
        bool has_final_method = false;
        AccessFlags promoted_flags;
        promoted_flags.set_flags(0);
        // These need to be oop pointers because they are allocated lazily
        // inside parse_methods inside a nested HandleMark
        objArrayOop methods_annotations_oop = NULL;
        objArrayOop methods_parameter_annotations_oop = NULL;
        objArrayOop methods_default_annotations_oop = NULL;
        objArrayHandle methods = parse_methods(cp, access_flags.is_interface(),
                                               &promoted_flags,
                                               &has_final_method,
                                               &methods_annotations_oop,
                                               &methods_parameter_annotations_oop,
                                               &methods_default_annotations_oop,
                                               CHECK_(nullHandle));

        objArrayHandle methods_annotations(THREAD, methods_annotations_oop);
        objArrayHandle methods_parameter_annotations(THREAD, methods_parameter_annotations_oop);
        objArrayHandle methods_default_annotations(THREAD, methods_default_annotations_oop);

  {- -------------------------------------------
  (1) (この段階までで, クラスファイルの中を(ほぼ)全てパースし終わり, フォーマットチェックも完了)
      ---------------------------------------- -}

  {- -------------------------------------------
  (1) 次に, スーパークラスのチェックを以下のように行う.
      ---------------------------------------- -}

        // We check super class after class file is parsed and format is checked

    {- -------------------------------------------
  (1.1) もしスーパークラスが存在し(= java/lang/Objectではなく), かつまだロードされてなければ,
        SystemDictionary::resolve_super_or_fail() でロードする.

        (ただし, パース対象のクラスがインターフェースの場合は
        スーパークラスは java/lang/Object でなければいけないので, 
        その場合はここでエラーを出す)
        ---------------------------------------- -}

        if (super_class_index > 0 && super_klass.is_null()) {
          Symbol*  sk  = cp->klass_name_at(super_class_index);
          if (access_flags.is_interface()) {
            // Before attempting to resolve the superclass, check for class format
            // errors not checked yet.
            guarantee_property(sk == vmSymbols::java_lang_Object(),
                               "Interfaces must have java.lang.Object as superclass in class file %s",
                               CHECK_(nullHandle));
          }
          klassOop k = SystemDictionary::resolve_super_or_fail(class_name,
                                                               sk,
                                                               class_loader,
                                                               protection_domain,
                                                               true,
                                                               CHECK_(nullHandle));

          KlassHandle kh (THREAD, k);
          super_klass = instanceKlassHandle(THREAD, kh());

    {- -------------------------------------------
  (1.1) ??
        ---------------------------------------- -}

          if (LinkWellKnownClasses)  // my super class is well known to me
            cp->klass_at_put(super_class_index, super_klass()); // eagerly resolve
        }

    {- -------------------------------------------
  (1.1) super_klass が null でない(= java/lang/Object ではない?) 場合は, 
        super_klass がインターフェースではなく, final クラスでもないことを確認.
        (もしインターフェースであれば IncompatibleClassChangeError, final クラスであれば VerifyError を出す)
        ---------------------------------------- -}

        if (super_klass.not_null()) {
          if (super_klass->is_interface()) {
            ResourceMark rm(THREAD);
            Exceptions::fthrow(
              THREAD_AND_LOCATION,
              vmSymbols::java_lang_IncompatibleClassChangeError(),
              "class %s has interface %s as super class",
              class_name->as_klass_external_name(),
              super_klass->external_name()
            );
            return nullHandle;
          }
          // Make sure super class is not final
          if (super_klass->is_final()) {
            THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle);
          }
        }

  {- -------------------------------------------
  (1) 実装しているインターフェースの推移的平方の数を計算し, その数にあった objArrayHandle を作成する.
      ---------------------------------------- -}

        // Compute the transitive list of all unique interfaces implemented by this class
        objArrayHandle transitive_interfaces = compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));

  {- -------------------------------------------
  (1) 全メソッドを名前順でソートし, vtable 中での index を割り振る.
      ---------------------------------------- -}

        // sort methods
        typeArrayHandle method_ordering = sort_methods(methods,
                                                       methods_annotations,
                                                       methods_parameter_annotations,
                                                       methods_default_annotations,
                                                       CHECK_(nullHandle));

  {- -------------------------------------------
  (1) ClassFileParser::parse_methods() の処理中で発見した「クラスのフラグに追加した方がいいフラグ」を access_flags に追加する.
      ---------------------------------------- -}

        // promote flags from parse_methods() to the klass' flags
        access_flags.add_promoted_flags(promoted_flags.as_int());

  {- -------------------------------------------
  (1) vtable, itable の大きさと miranda method の個数を計算する.
      ---------------------------------------- -}

        // Size of Java vtable (in words)
        int vtable_size = 0;
        int itable_size = 0;
        int num_miranda_methods = 0;

        klassVtable::compute_vtable_size_and_num_mirandas(vtable_size,
                                                          num_miranda_methods,
                                                          super_klass(),
                                                          methods(),
                                                          access_flags,
                                                          class_loader,
                                                          class_name,
                                                          local_interfaces(),
                                                          CHECK_(nullHandle));

        // Size of Java itable (in words)
        itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);

  {- -------------------------------------------
  (1) 各フィールドについて, オブジェクト内でのオフセットを決める. (#TODO)
      型が同じものごとにまとめて配置している模様. まとめ方は FieldsAllocationStyle 等により変更できる模様 (#TODO)
      (なお, ClassFileParser::parse_fields() に渡しておいた FieldAllocationCount 型の引数("fac")より, 各型のフィールド数は分かっている)
      ---------------------------------------- -}

        // Field size and offset computation
        int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size();
    #ifndef PRODUCT
        int orig_nonstatic_field_size = 0;
    #endif
        int static_field_size = 0;
        int next_static_oop_offset;
        int next_static_double_offset;
        int next_static_word_offset;
        int next_static_short_offset;
        int next_static_byte_offset;
        int next_static_type_offset;
        int next_nonstatic_oop_offset;
        int next_nonstatic_double_offset;
        int next_nonstatic_word_offset;
        int next_nonstatic_short_offset;
        int next_nonstatic_byte_offset;
        int next_nonstatic_type_offset;
        int first_nonstatic_oop_offset;
        int first_nonstatic_field_offset;
        int next_nonstatic_field_offset;

        // Calculate the starting byte offsets
        next_static_oop_offset      = instanceMirrorKlass::offset_of_static_fields();
        next_static_double_offset   = next_static_oop_offset +
                                      (fac.static_oop_count * heapOopSize);
        if ( fac.static_double_count &&
             (Universe::field_type_should_be_aligned(T_DOUBLE) ||
              Universe::field_type_should_be_aligned(T_LONG)) ) {
          next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong);
        }

        next_static_word_offset     = next_static_double_offset +
                                      (fac.static_double_count * BytesPerLong);
        next_static_short_offset    = next_static_word_offset +
                                      (fac.static_word_count * BytesPerInt);
        next_static_byte_offset     = next_static_short_offset +
                                      (fac.static_short_count * BytesPerShort);
        next_static_type_offset     = align_size_up((next_static_byte_offset +
                                      fac.static_byte_count ), wordSize );
        static_field_size           = (next_static_type_offset -
                                      next_static_oop_offset) / wordSize;

        // Add fake fields for java.lang.Class instances (also see below)
        if (class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) {
          java_lang_Class_fix_pre(&nonstatic_field_size, &fac);
        }

        first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() +
                                       nonstatic_field_size * heapOopSize;
        next_nonstatic_field_offset = first_nonstatic_field_offset;

        // adjust the vmentry field declaration in java.lang.invoke.MethodHandle
        if (EnableInvokeDynamic && class_name == vmSymbols::java_lang_invoke_MethodHandle() && class_loader.is_null()) {
          java_lang_invoke_MethodHandle_fix_pre(cp, fields, &fac, CHECK_(nullHandle));
        }

        // Add a fake "discovered" field if it is not present
        // for compatibility with earlier jdk's.
        if (class_name == vmSymbols::java_lang_ref_Reference()
          && class_loader.is_null()) {
          java_lang_ref_Reference_fix_pre(&fields, cp, &fac, CHECK_(nullHandle));
        }
        // end of "discovered" field compactibility fix

        unsigned int nonstatic_double_count = fac.nonstatic_double_count;
        unsigned int nonstatic_word_count   = fac.nonstatic_word_count;
        unsigned int nonstatic_short_count  = fac.nonstatic_short_count;
        unsigned int nonstatic_byte_count   = fac.nonstatic_byte_count;
        unsigned int nonstatic_oop_count    = fac.nonstatic_oop_count;

        bool super_has_nonstatic_fields =
                (super_klass() != NULL && super_klass->has_nonstatic_fields());
        bool has_nonstatic_fields  =  super_has_nonstatic_fields ||
                ((nonstatic_double_count + nonstatic_word_count +
                  nonstatic_short_count + nonstatic_byte_count +
                  nonstatic_oop_count) != 0);


        // Prepare list of oops for oop map generation.
        int* nonstatic_oop_offsets;
        unsigned int* nonstatic_oop_counts;
        unsigned int nonstatic_oop_map_count = 0;

        nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, int, nonstatic_oop_count + 1);
        nonstatic_oop_counts  = NEW_RESOURCE_ARRAY_IN_THREAD(
                  THREAD, unsigned int, nonstatic_oop_count + 1);

        // Add fake fields for java.lang.Class instances (also see above).
        // FieldsAllocationStyle and CompactFields values will be reset to default.
        if(class_name == vmSymbols::java_lang_Class() && class_loader.is_null()) {
          java_lang_Class_fix_post(&next_nonstatic_field_offset);
          nonstatic_oop_offsets[0] = first_nonstatic_field_offset;
          const uint fake_oop_count = (next_nonstatic_field_offset -
                                       first_nonstatic_field_offset) / heapOopSize;
          nonstatic_oop_counts[0] = fake_oop_count;
          nonstatic_oop_map_count = 1;
          nonstatic_oop_count -= fake_oop_count;
          first_nonstatic_oop_offset = first_nonstatic_field_offset;
        } else {
          first_nonstatic_oop_offset = 0; // will be set for first oop field
        }

    #ifndef PRODUCT
        if( PrintCompactFieldsSavings ) {
          next_nonstatic_double_offset = next_nonstatic_field_offset +
                                         (nonstatic_oop_count * heapOopSize);
          if ( nonstatic_double_count > 0 ) {
            next_nonstatic_double_offset = align_size_up(next_nonstatic_double_offset, BytesPerLong);
          }
          next_nonstatic_word_offset  = next_nonstatic_double_offset +
                                        (nonstatic_double_count * BytesPerLong);
          next_nonstatic_short_offset = next_nonstatic_word_offset +
                                        (nonstatic_word_count * BytesPerInt);
          next_nonstatic_byte_offset  = next_nonstatic_short_offset +
                                        (nonstatic_short_count * BytesPerShort);
          next_nonstatic_type_offset  = align_size_up((next_nonstatic_byte_offset +
                                        nonstatic_byte_count ), heapOopSize );
          orig_nonstatic_field_size   = nonstatic_field_size +
          ((next_nonstatic_type_offset - first_nonstatic_field_offset)/heapOopSize);
        }
    #endif
        bool compact_fields   = CompactFields;
        int  allocation_style = FieldsAllocationStyle;
        if( allocation_style < 0 || allocation_style > 2 ) { // Out of range?
          assert(false, "0 <= FieldsAllocationStyle <= 2");
          allocation_style = 1; // Optimistic
        }

        // The next classes have predefined hard-coded fields offsets
        // (see in JavaClasses::compute_hard_coded_offsets()).
        // Use default fields allocation order for them.
        if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() &&
            (class_name == vmSymbols::java_lang_AssertionStatusDirectives() ||
             class_name == vmSymbols::java_lang_Class() ||
             class_name == vmSymbols::java_lang_ClassLoader() ||
             class_name == vmSymbols::java_lang_ref_Reference() ||
             class_name == vmSymbols::java_lang_ref_SoftReference() ||
             class_name == vmSymbols::java_lang_StackTraceElement() ||
             class_name == vmSymbols::java_lang_String() ||
             class_name == vmSymbols::java_lang_Throwable() ||
             class_name == vmSymbols::java_lang_Boolean() ||
             class_name == vmSymbols::java_lang_Character() ||
             class_name == vmSymbols::java_lang_Float() ||
             class_name == vmSymbols::java_lang_Double() ||
             class_name == vmSymbols::java_lang_Byte() ||
             class_name == vmSymbols::java_lang_Short() ||
             class_name == vmSymbols::java_lang_Integer() ||
             class_name == vmSymbols::java_lang_Long())) {
          allocation_style = 0;     // Allocate oops first
          compact_fields   = false; // Don't compact fields
        }

        if( allocation_style == 0 ) {
          // Fields order: oops, longs/doubles, ints, shorts/chars, bytes
          next_nonstatic_oop_offset    = next_nonstatic_field_offset;
          next_nonstatic_double_offset = next_nonstatic_oop_offset +
                                          (nonstatic_oop_count * heapOopSize);
        } else if( allocation_style == 1 ) {
          // Fields order: longs/doubles, ints, shorts/chars, bytes, oops
          next_nonstatic_double_offset = next_nonstatic_field_offset;
        } else if( allocation_style == 2 ) {
          // Fields allocation: oops fields in super and sub classes are together.
          if( nonstatic_field_size > 0 && super_klass() != NULL &&
              super_klass->nonstatic_oop_map_size() > 0 ) {
            int map_size = super_klass->nonstatic_oop_map_size();
            OopMapBlock* first_map = super_klass->start_of_nonstatic_oop_maps();
            OopMapBlock* last_map = first_map + map_size - 1;
            int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
            if (next_offset == next_nonstatic_field_offset) {
              allocation_style = 0;   // allocate oops first
              next_nonstatic_oop_offset    = next_nonstatic_field_offset;
              next_nonstatic_double_offset = next_nonstatic_oop_offset +
                                             (nonstatic_oop_count * heapOopSize);
            }
          }
          if( allocation_style == 2 ) {
            allocation_style = 1;     // allocate oops last
            next_nonstatic_double_offset = next_nonstatic_field_offset;
          }
        } else {
          ShouldNotReachHere();
        }

        int nonstatic_oop_space_count   = 0;
        int nonstatic_word_space_count  = 0;
        int nonstatic_short_space_count = 0;
        int nonstatic_byte_space_count  = 0;
        int nonstatic_oop_space_offset;
        int nonstatic_word_space_offset;
        int nonstatic_short_space_offset;
        int nonstatic_byte_space_offset;

        if( nonstatic_double_count > 0 ) {
          int offset = next_nonstatic_double_offset;
          next_nonstatic_double_offset = align_size_up(offset, BytesPerLong);
          if( compact_fields && offset != next_nonstatic_double_offset ) {
            // Allocate available fields into the gap before double field.
            int length = next_nonstatic_double_offset - offset;
            assert(length == BytesPerInt, "");
            nonstatic_word_space_offset = offset;
            if( nonstatic_word_count > 0 ) {
              nonstatic_word_count      -= 1;
              nonstatic_word_space_count = 1; // Only one will fit
              length -= BytesPerInt;
              offset += BytesPerInt;
            }
            nonstatic_short_space_offset = offset;
            while( length >= BytesPerShort && nonstatic_short_count > 0 ) {
              nonstatic_short_count       -= 1;
              nonstatic_short_space_count += 1;
              length -= BytesPerShort;
              offset += BytesPerShort;
            }
            nonstatic_byte_space_offset = offset;
            while( length > 0 && nonstatic_byte_count > 0 ) {
              nonstatic_byte_count       -= 1;
              nonstatic_byte_space_count += 1;
              length -= 1;
            }
            // Allocate oop field in the gap if there are no other fields for that.
            nonstatic_oop_space_offset = offset;
            if( length >= heapOopSize && nonstatic_oop_count > 0 &&
                allocation_style != 0 ) { // when oop fields not first
              nonstatic_oop_count      -= 1;
              nonstatic_oop_space_count = 1; // Only one will fit
              length -= heapOopSize;
              offset += heapOopSize;
            }
          }
        }

        next_nonstatic_word_offset  = next_nonstatic_double_offset +
                                      (nonstatic_double_count * BytesPerLong);
        next_nonstatic_short_offset = next_nonstatic_word_offset +
                                      (nonstatic_word_count * BytesPerInt);
        next_nonstatic_byte_offset  = next_nonstatic_short_offset +
                                      (nonstatic_short_count * BytesPerShort);

        int notaligned_offset;
        if( allocation_style == 0 ) {
          notaligned_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
        } else { // allocation_style == 1
          next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
          if( nonstatic_oop_count > 0 ) {
            next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize);
          }
          notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
        }
        next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize );
        nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset
                                       - first_nonstatic_field_offset)/heapOopSize);

        // Iterate over fields again and compute correct offsets.
        // The field allocation type was temporarily stored in the offset slot.
        // oop fields are located before non-oop fields (static and non-static).
        int len = fields->length();
        for (int i = 0; i < len; i += instanceKlass::next_offset) {
          int real_offset;
          FieldAllocationType atype = (FieldAllocationType) fields->ushort_at(i + instanceKlass::low_offset);
          switch (atype) {
            case STATIC_OOP:
              real_offset = next_static_oop_offset;
              next_static_oop_offset += heapOopSize;
              break;
            case STATIC_BYTE:
              real_offset = next_static_byte_offset;
              next_static_byte_offset += 1;
              break;
            case STATIC_SHORT:
              real_offset = next_static_short_offset;
              next_static_short_offset += BytesPerShort;
              break;
            case STATIC_WORD:
              real_offset = next_static_word_offset;
              next_static_word_offset += BytesPerInt;
              break;
            case STATIC_ALIGNED_DOUBLE:
            case STATIC_DOUBLE:
              real_offset = next_static_double_offset;
              next_static_double_offset += BytesPerLong;
              break;
            case NONSTATIC_OOP:
              if( nonstatic_oop_space_count > 0 ) {
                real_offset = nonstatic_oop_space_offset;
                nonstatic_oop_space_offset += heapOopSize;
                nonstatic_oop_space_count  -= 1;
              } else {
                real_offset = next_nonstatic_oop_offset;
                next_nonstatic_oop_offset += heapOopSize;
              }
              // Update oop maps
              if( nonstatic_oop_map_count > 0 &&
                  nonstatic_oop_offsets[nonstatic_oop_map_count - 1] ==
                  real_offset -
                  int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) *
                  heapOopSize ) {
                // Extend current oop map
                nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1;
              } else {
                // Create new oop map
                nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
                nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
                nonstatic_oop_map_count += 1;
                if( first_nonstatic_oop_offset == 0 ) { // Undefined
                  first_nonstatic_oop_offset = real_offset;
                }
              }
              break;
            case NONSTATIC_BYTE:
              if( nonstatic_byte_space_count > 0 ) {
                real_offset = nonstatic_byte_space_offset;
                nonstatic_byte_space_offset += 1;
                nonstatic_byte_space_count  -= 1;
              } else {
                real_offset = next_nonstatic_byte_offset;
                next_nonstatic_byte_offset += 1;
              }
              break;
            case NONSTATIC_SHORT:
              if( nonstatic_short_space_count > 0 ) {
                real_offset = nonstatic_short_space_offset;
                nonstatic_short_space_offset += BytesPerShort;
                nonstatic_short_space_count  -= 1;
              } else {
                real_offset = next_nonstatic_short_offset;
                next_nonstatic_short_offset += BytesPerShort;
              }
              break;
            case NONSTATIC_WORD:
              if( nonstatic_word_space_count > 0 ) {
                real_offset = nonstatic_word_space_offset;
                nonstatic_word_space_offset += BytesPerInt;
                nonstatic_word_space_count  -= 1;
              } else {
                real_offset = next_nonstatic_word_offset;
                next_nonstatic_word_offset += BytesPerInt;
              }
              break;
            case NONSTATIC_ALIGNED_DOUBLE:
            case NONSTATIC_DOUBLE:
              real_offset = next_nonstatic_double_offset;
              next_nonstatic_double_offset += BytesPerLong;
              break;
            default:
              ShouldNotReachHere();
          }
          fields->short_at_put(i + instanceKlass::low_offset,  extract_low_short_from_int(real_offset));
          fields->short_at_put(i + instanceKlass::high_offset, extract_high_short_from_int(real_offset));
        }

        // Size of instances
        int instance_size;

        next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize );
        instance_size = align_object_size(next_nonstatic_type_offset / wordSize);

        assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value");

  {- -------------------------------------------
  (1) oopmap の大きさ(= OopMapBlock オブジェクトが占める大きさ)を計算する.
      ---------------------------------------- -}

        // Number of non-static oop map blocks allocated at end of klass.
        const unsigned int total_oop_map_count =
          compute_oop_map_count(super_klass, nonstatic_oop_map_count,
                                first_nonstatic_oop_offset);

  {- -------------------------------------------
  (1) reference type かどうか (= java.lang.ref.Reference クラスのサブクラスかどうか) を調べる
      ---------------------------------------- -}

        // Compute reference type
        ReferenceType rt;
        if (super_klass() == NULL) {
          rt = REF_NONE;
        } else {
          rt = super_klass->reference_type();
        }

  {- -------------------------------------------
  (1) パース結果を格納するための klassOop を確保する.
      ---------------------------------------- -}

        // We can now create the basic klassOop for this klass
        klassOop ik = oopFactory::new_instanceKlass(name, vtable_size, itable_size,
                                                    static_field_size,
                                                    total_oop_map_count,
                                                    rt, CHECK_(nullHandle));
        instanceKlassHandle this_klass (THREAD, ik);

  {- -------------------------------------------
  (1) (assert 処理)
      ---------------------------------------- -}

        assert(this_klass->static_field_size() == static_field_size, "sanity");
        assert(this_klass->nonstatic_oop_map_count() == total_oop_map_count,
               "sanity");

  {- -------------------------------------------
  (1) 確保した klassOop 内にパース結果の情報を書き込んでいく.

      (処理途中に, ClassFileParser::parse_classfile_attributes() による
       クラスファイルのアトリビュートのパース処理が入っている模様.
       処理はフィールドやメソッドのアトリビュートのパースとほぼ同様)
      (また, oopmap 領域への書き込みは ClassFileParser::fill_oop_maps() で行われている)
      ---------------------------------------- -}

        // Fill in information already parsed
        this_klass->set_access_flags(access_flags);
        this_klass->set_should_verify_class(verify);
        jint lh = Klass::instance_layout_helper(instance_size, false);
        this_klass->set_layout_helper(lh);
        assert(this_klass->oop_is_instance(), "layout is correct");
        assert(this_klass->size_helper() == instance_size, "correct size_helper");
        // Not yet: supers are done below to support the new subtype-checking fields
        //this_klass->set_super(super_klass());
        this_klass->set_class_loader(class_loader());
        this_klass->set_nonstatic_field_size(nonstatic_field_size);
        this_klass->set_has_nonstatic_fields(has_nonstatic_fields);
        this_klass->set_static_oop_field_count(fac.static_oop_count);
        cp->set_pool_holder(this_klass());
        error_handler.set_in_error(false);   // turn off error handler for cp
        this_klass->set_constants(cp());
        this_klass->set_local_interfaces(local_interfaces());
        this_klass->set_fields(fields());
        this_klass->set_methods(methods());
        if (has_final_method) {
          this_klass->set_has_final_method();
        }
        this_klass->set_method_ordering(method_ordering());
        // The instanceKlass::_methods_jmethod_ids cache and the
        // instanceKlass::_methods_cached_itable_indices cache are
        // both managed on the assumption that the initial cache
        // size is equal to the number of methods in the class. If
        // that changes, then instanceKlass::idnum_can_increment()
        // has to be changed accordingly.
        this_klass->set_initial_method_idnum(methods->length());
        this_klass->set_name(cp->klass_name_at(this_class_index));
        if (LinkWellKnownClasses || is_anonymous())  // I am well known to myself
          cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
        this_klass->set_protection_domain(protection_domain());
        this_klass->set_fields_annotations(fields_annotations());
        this_klass->set_methods_annotations(methods_annotations());
        this_klass->set_methods_parameter_annotations(methods_parameter_annotations());
        this_klass->set_methods_default_annotations(methods_default_annotations());

        this_klass->set_minor_version(minor_version);
        this_klass->set_major_version(major_version);

        // Set up methodOop::intrinsic_id as soon as we know the names of methods.
        // (We used to do this lazily, but now we query it in Rewriter,
        // which is eagerly done for every method, so we might as well do it now,
        // when everything is fresh in memory.)
        if (methodOopDesc::klass_id_for_intrinsics(this_klass->as_klassOop()) != vmSymbols::NO_SID) {
          for (int j = 0; j < methods->length(); j++) {
            ((methodOop)methods->obj_at(j))->init_intrinsic_id();
          }
        }

        if (cached_class_file_bytes != NULL) {
          // JVMTI: we have an instanceKlass now, tell it about the cached bytes
          this_klass->set_cached_class_file(cached_class_file_bytes,
                                            cached_class_file_length);
        }

        // Miranda methods
        if ((num_miranda_methods > 0) ||
            // if this class introduced new miranda methods or
            (super_klass.not_null() && (super_klass->has_miranda_methods()))
            // super class exists and this class inherited miranda methods
            ) {
          this_klass->set_has_miranda_methods(); // then set a flag
        }

        // Additional attributes
        parse_classfile_attributes(cp, this_klass, CHECK_(nullHandle));

        // Make sure this is the end of class file stream
        guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));

        // VerifyOops believes that once this has been set, the object is completely loaded.
        // Compute transitive closure of interfaces this class implements
        this_klass->set_transitive_interfaces(transitive_interfaces());

        // Fill in information needed to compute superclasses.
        this_klass->initialize_supers(super_klass(), CHECK_(nullHandle));

        // Initialize itable offset tables
        klassItable::setup_itable_offset_table(this_klass);

        // Do final class setup
        fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts);

        set_precomputed_flags(this_klass);

        // reinitialize modifiers, using the InnerClasses attribute
        int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
        this_klass->set_modifier_flags(computed_modifiers);

  {- -------------------------------------------
  (1) 正しいクラスになっていることをチェックする.
      ---------------------------------------- -}

        // check if this class can access its super class
        check_super_class_access(this_klass, CHECK_(nullHandle));

        // check if this class can access its superinterfaces
        check_super_interface_access(this_klass, CHECK_(nullHandle));

        // check if this class overrides any final method
        check_final_method_override(this_klass, CHECK_(nullHandle));

        // check that if this class is an interface then it doesn't have static methods
        if (this_klass->is_interface()) {
          check_illegal_static_method(this_klass, CHECK_(nullHandle));
        }

  {- -------------------------------------------
  (1) java_lang_Class::create_mirror() を呼んで mirror を生成する.
      ---------------------------------------- -}

        // Allocate mirror and initialize static fields
        java_lang_Class::create_mirror(this_klass, CHECK_(nullHandle));

  {- -------------------------------------------
  (1) (JMM のフック点)
      (DTrace のフック点)にもなっているが... (See: ClassLoadingService::notify_class_loaded())
      ---------------------------------------- -}

        ClassLoadingService::notify_class_loaded(instanceKlass::cast(this_klass()),
                                                 false /* not shared class */);

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

        if (TraceClassLoading) {
          // print in a single call to reduce interleaving of output
          if (cfs->source() != NULL) {
            tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
                       cfs->source());
          } else if (class_loader.is_null()) {
            if (THREAD->is_Java_thread()) {
              klassOop caller = ((JavaThread*)THREAD)->security_get_caller_class(1);
              tty->print("[Loaded %s by instance of %s]\n",
                         this_klass->external_name(),
                         instanceKlass::cast(caller)->external_name());
            } else {
              tty->print("[Loaded %s]\n", this_klass->external_name());
            }
          } else {
            ResourceMark rm;
            tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
                       instanceKlass::cast(class_loader->klass())->external_name());
          }
        }

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

        if (TraceClassResolution) {
          // print out the superclass.
          const char * from = Klass::cast(this_klass())->external_name();
          if (this_klass->java_super() != NULL) {
            tty->print("RESOLVE %s %s (super)\n", from, instanceKlass::cast(this_klass->java_super())->external_name());
          }
          // print out each of the interface classes referred to by this class.
          objArrayHandle local_interfaces(THREAD, this_klass->local_interfaces());
          if (!local_interfaces.is_null()) {
            int length = local_interfaces->length();
            for (int i = 0; i < length; i++) {
              klassOop k = klassOop(local_interfaces->obj_at(i));
              instanceKlass* to_class = instanceKlass::cast(k);
              const char * to = to_class->external_name();
              tty->print("RESOLVE %s %s (interface)\n", from, to);
            }
          }
        }

  {- -------------------------------------------
  (1) (トレース出力)
      ---------------------------------------- -}

    #ifndef PRODUCT
        if( PrintCompactFieldsSavings ) {
          if( nonstatic_field_size < orig_nonstatic_field_size ) {
            tty->print("[Saved %d of %d bytes in %s]\n",
                     (orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize,
                     orig_nonstatic_field_size*heapOopSize,
                     this_klass->external_name());
          } else if( nonstatic_field_size > orig_nonstatic_field_size ) {
            tty->print("[Wasted %d over %d bytes in %s]\n",
                     (nonstatic_field_size - orig_nonstatic_field_size)*heapOopSize,
                     orig_nonstatic_field_size*heapOopSize,
                     this_klass->external_name());
          }
        }
    #endif

  {- -------------------------------------------
  (1) パース結果である this_klass Handle の中身を HandleMark 外に待避.
      ---------------------------------------- -}

        // preserve result across HandleMark
        preserve_this_klass = this_klass();
      }

  {- -------------------------------------------
  (1) パース結果を再度 Handle に包み直して, 呼び出し元にリターン.
      ---------------------------------------- -}

      // Create new handle outside HandleMark
      instanceKlassHandle this_klass (THREAD, preserve_this_klass);
      debug_only(this_klass->as_klassOop()->verify();)

      return this_klass;

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