< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page
*** 70,10 ***
--- 70,11 ---
  #include "oops/klass.inline.hpp"
  #include "oops/method.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/recordComponent.hpp"
  #include "oops/symbol.hpp"
+ #include "oops/inlineKlass.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/jvmtiRedefineClasses.hpp"
  #include "prims/jvmtiThreadState.hpp"
  #include "prims/methodComparator.hpp"
  #include "runtime/arguments.hpp"

*** 146,10 ***
--- 147,15 ---
  #define DTRACE_CLASSINIT_PROBE(type, thread_type)
  #define DTRACE_CLASSINIT_PROBE_WAIT(type, thread_type, wait)
  
  #endif //  ndef DTRACE_ENABLED
  
+ void InlineLayoutInfo::metaspace_pointers_do(MetaspaceClosure* it) {
+   log_trace(cds)("Iter(InlineFieldInfo): %p", this);
+   it->push(&_klass);
+ }
+ 
  bool InstanceKlass::_finalization_enabled = true;
  
  static inline bool is_class_loader(const Symbol* class_name,
                                     const ClassFileParser& parser) {
    assert(class_name != nullptr, "invariant");

*** 167,10 ***
--- 173,23 ---
      }
    }
    return false;
  }
  
+ bool InstanceKlass::field_is_null_free_inline_type(int index) const {
+   return field(index).field_flags().is_null_free_inline_type();
+ }
+ 
+ bool InstanceKlass::is_class_in_loadable_descriptors_attribute(Symbol* name) const {
+   if (_loadable_descriptors == nullptr) return false;
+   for (int i = 0; i < _loadable_descriptors->length(); i++) {
+         Symbol* class_name = _constants->symbol_at(_loadable_descriptors->at(i));
+         if (class_name == name) return true;
+   }
+   return false;
+ }
+ 
  static inline bool is_stack_chunk_class(const Symbol* class_name,
                                          const ClassLoaderData* loader_data) {
    return (class_name == vmSymbols::jdk_internal_vm_StackChunk() &&
            loader_data->is_the_null_class_loader_data());
  }

*** 444,11 ***
  
  InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
    const int size = InstanceKlass::size(parser.vtable_size(),
                                         parser.itable_size(),
                                         nonstatic_oop_map_size(parser.total_oop_map_count()),
!                                        parser.is_interface());
  
    const Symbol* const class_name = parser.class_name();
    assert(class_name != nullptr, "invariant");
    ClassLoaderData* loader_data = parser.loader_data();
    assert(loader_data != nullptr, "invariant");
--- 463,12 ---
  
  InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
    const int size = InstanceKlass::size(parser.vtable_size(),
                                         parser.itable_size(),
                                         nonstatic_oop_map_size(parser.total_oop_map_count()),
!                                        parser.is_interface(),
+                                        parser.is_inline_type());
  
    const Symbol* const class_name = parser.class_name();
    assert(class_name != nullptr, "invariant");
    ClassLoaderData* loader_data = parser.loader_data();
    assert(loader_data != nullptr, "invariant");

*** 467,10 ***
--- 487,13 ---
      // stack chunk
      ik = new (loader_data, size, use_class_space, THREAD) InstanceStackChunkKlass(parser);
    } else if (is_class_loader(class_name, parser)) {
      // class loader - java.lang.ClassLoader
      ik = new (loader_data, size, use_class_space, THREAD) InstanceClassLoaderKlass(parser);
+   } else if (parser.is_inline_type()) {
+     // inline type
+     ik = new (loader_data, size, use_class_space, THREAD) InlineKlass(parser);
    } else {
      // normal
      ik = new (loader_data, size, use_class_space, THREAD) InstanceKlass(parser);
    }
  

*** 478,13 ***
--- 501,42 ---
    // class count.  Can get OOM here.
    if (HAS_PENDING_EXCEPTION) {
      return nullptr;
    }
  
+ #ifdef ASSERT
+   ik->bounds_check((address) ik->start_of_vtable(), false, size);
+   ik->bounds_check((address) ik->start_of_itable(), false, size);
+   ik->bounds_check((address) ik->end_of_itable(), true, size);
+   ik->bounds_check((address) ik->end_of_nonstatic_oop_maps(), true, size);
+ #endif //ASSERT
    return ik;
  }
  
+ #ifndef PRODUCT
+ bool InstanceKlass::bounds_check(address addr, bool edge_ok, intptr_t size_in_bytes) const {
+   const char* bad = nullptr;
+   address end = nullptr;
+   if (addr < (address)this) {
+     bad = "before";
+   } else if (addr == (address)this) {
+     if (edge_ok)  return true;
+     bad = "just before";
+   } else if (addr == (end = (address)this + sizeof(intptr_t) * (size_in_bytes < 0 ? size() : size_in_bytes))) {
+     if (edge_ok)  return true;
+     bad = "just after";
+   } else if (addr > end) {
+     bad = "after";
+   } else {
+     return true;
+   }
+   tty->print_cr("%s object bounds: " INTPTR_FORMAT " [" INTPTR_FORMAT ".." INTPTR_FORMAT "]",
+       bad, (intptr_t)addr, (intptr_t)this, (intptr_t)end);
+   Verbose = WizardMode = true; this->print(); //@@
+   return false;
+ }
+ #endif //PRODUCT
  
  // copy method ordering from resource area to Metaspace
  void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
    if (m != nullptr) {
      // allocate a new array and copy contents (memcpy?)

*** 520,17 ***
    _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
    _itable_len(parser.itable_size()),
    _nest_host_index(0),
    _init_state(allocated),
    _reference_type(reference_type),
!   _init_thread(nullptr)
  {
    set_vtable_length(parser.vtable_size());
    set_access_flags(parser.access_flags());
    if (parser.is_hidden()) set_is_hidden();
    set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                      false));
  
    assert(nullptr == _methods, "underlying memory not zeroed?");
    assert(is_instance_klass(), "is layout incorrect?");
    assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
  }
--- 572,23 ---
    _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
    _itable_len(parser.itable_size()),
    _nest_host_index(0),
    _init_state(allocated),
    _reference_type(reference_type),
!   _init_thread(nullptr),
+   _inline_layout_info_array(nullptr),
+   _loadable_descriptors(nullptr),
+   _adr_inlineklass_fixed_block(nullptr)
  {
    set_vtable_length(parser.vtable_size());
    set_access_flags(parser.access_flags());
    if (parser.is_hidden()) set_is_hidden();
    set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                      false));
+   if (parser.has_inline_fields()) {
+     set_has_inline_type_fields();
+   }
  
    assert(nullptr == _methods, "underlying memory not zeroed?");
    assert(is_instance_klass(), "is layout incorrect?");
    assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
  }

*** 666,10 ***
--- 724,15 ---
    if (fields_status() != nullptr && !fields_status()->is_shared()) {
      MetadataFactory::free_array<FieldStatus>(loader_data, fields_status());
    }
    set_fields_status(nullptr);
  
+   if (inline_layout_info_array() != nullptr) {
+     MetadataFactory::free_array<InlineLayoutInfo>(loader_data, inline_layout_info_array());
+   }
+   set_inline_layout_info_array(nullptr);
+ 
    // If a method from a redefined class is using this constant pool, don't
    // delete it, yet.  The new class's previous version will point to this.
    if (constants() != nullptr) {
      assert (!constants()->on_stack(), "shouldn't be called if anything is onstack");
      if (!constants()->is_shared()) {

*** 700,10 ***
--- 763,17 ---
        !permitted_subclasses()->is_shared()) {
      MetadataFactory::free_array<jushort>(loader_data, permitted_subclasses());
    }
    set_permitted_subclasses(nullptr);
  
+   if (loadable_descriptors() != nullptr &&
+       loadable_descriptors() != Universe::the_empty_short_array() &&
+       !loadable_descriptors()->is_shared()) {
+     MetadataFactory::free_array<jushort>(loader_data, loadable_descriptors());
+   }
+   set_loadable_descriptors(nullptr);
+ 
    // We should deallocate the Annotations instance if it's not in shared spaces.
    if (annotations() != nullptr && !annotations()->is_shared()) {
      MetadataFactory::free_metadata(loader_data, annotations());
    }
    set_annotations(nullptr);

*** 858,10 ***
--- 928,116 ---
    for (int index = 0; index < num_interfaces; index++) {
      InstanceKlass* interk = interfaces->at(index);
      interk->link_class_impl(CHECK_false);
    }
  
+ 
+   // If a class declares a method that uses an inline class as an argument
+   // type or return inline type, this inline class must be loaded during the
+   // linking of this class because size and properties of the inline class
+   // must be known in order to be able to perform inline type optimizations.
+   // The implementation below is an approximation of this rule, the code
+   // iterates over all methods of the current class (including overridden
+   // methods), not only the methods declared by this class. This
+   // approximation makes the code simpler, and doesn't change the semantic
+   // because classes declaring methods overridden by the current class are
+   // linked (and have performed their own pre-loading) before the linking
+   // of the current class.
+ 
+ 
+   // Note:
+   // Inline class types are loaded during
+   // the loading phase (see ClassFileParser::post_process_parsed_stream()).
+   // Inline class types used as element types for array creation
+   // are not pre-loaded. Their loading is triggered by either anewarray
+   // or multianewarray bytecodes.
+ 
+   // Could it be possible to do the following processing only if the
+   // class uses inline types?
+   if (EnableValhalla) {
+     ResourceMark rm(THREAD);
+     for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+       if (fs.is_null_free_inline_type() && fs.access_flags().is_static()) {
+         Symbol* sig = fs.signature();
+         TempNewSymbol s = Signature::strip_envelope(sig);
+         if (s != name()) {
+           log_info(class, preload)("Preloading class %s during linking of class %s. Cause: a null-free static field is declared with this type", s->as_C_string(), name()->as_C_string());
+           Klass* klass = SystemDictionary::resolve_or_fail(s,
+                                                           Handle(THREAD, class_loader()), Handle(THREAD, protection_domain()), true,
+                                                           CHECK_false);
+           if (HAS_PENDING_EXCEPTION) {
+             log_warning(class, preload)("Preloading of class %s during linking of class %s (cause: null-free static field) failed: %s",
+                                       s->as_C_string(), name()->as_C_string(), PENDING_EXCEPTION->klass()->name()->as_C_string());
+             return false; // Exception is still pending
+           }
+           log_info(class, preload)("Preloading of class %s during linking of class %s (cause: null-free static field) succeeded",
+                                    s->as_C_string(), name()->as_C_string());
+           assert(klass != nullptr, "Sanity check");
+           if (klass->is_abstract()) {
+             THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(),
+                       err_msg("Class %s expects class %s to be concrete value class, but it is an abstract class",
+                       name()->as_C_string(),
+                       InstanceKlass::cast(klass)->external_name()), false);
+           }
+           if (!klass->is_inline_klass()) {
+             THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(),
+                        err_msg("class %s expects class %s to be a value class but it is an identity class",
+                        name()->as_C_string(), klass->external_name()), false);
+           }
+           InlineKlass* vk = InlineKlass::cast(klass);
+           if (!vk->is_implicitly_constructible()) {
+              THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(),
+                         err_msg("class %s is not implicitly constructible and it is used in a null restricted static field (not supported)",
+                         klass->external_name()), false);
+           }
+           // the inline_type_field_klasses_array might have been loaded with CDS, so update only if not already set and check consistency
+           InlineLayoutInfo* li = inline_layout_info_adr(fs.index());
+           if (li->klass() == nullptr) {
+             li->set_klass(InlineKlass::cast(vk));
+             li->set_kind(LayoutKind::REFERENCE);
+           }
+           assert(get_inline_type_field_klass(fs.index()) == vk, "Must match");
+         } else {
+           InlineLayoutInfo* li = inline_layout_info_adr(fs.index());
+           if (li->klass() == nullptr) {
+             li->set_klass(InlineKlass::cast(this));
+             li->set_kind(LayoutKind::REFERENCE);
+           }
+           assert(get_inline_type_field_klass(fs.index()) == this, "Must match");
+         }
+       }
+     }
+ 
+     // Aggressively preloading all classes from the LoadableDescriptors attribute
+     if (loadable_descriptors() != nullptr) {
+       HandleMark hm(THREAD);
+       for (int i = 0; i < loadable_descriptors()->length(); i++) {
+         Symbol* sig = constants()->symbol_at(loadable_descriptors()->at(i));
+         if (!Signature::has_envelope(sig)) continue;
+         TempNewSymbol class_name = Signature::strip_envelope(sig);
+         if (class_name == name()) continue;
+         log_info(class, preload)("Preloading class %s during linking of class %s because of the class is listed in the LoadableDescriptors attribute", sig->as_C_string(), name()->as_C_string());
+         oop loader = class_loader();
+         oop protection_domain = this->protection_domain();
+         Klass* klass = SystemDictionary::resolve_or_null(class_name,
+                                                          Handle(THREAD, loader), Handle(THREAD, protection_domain), THREAD);
+         if (HAS_PENDING_EXCEPTION) {
+           CLEAR_PENDING_EXCEPTION;
+         }
+         if (klass != nullptr) {
+           log_info(class, preload)("Preloading of class %s during linking of class %s (cause: LoadableDescriptors attribute) succeeded", class_name->as_C_string(), name()->as_C_string());
+           if (!klass->is_inline_klass()) {
+             // Non value class are allowed by the current spec, but it could be an indication of an issue so let's log a warning
+               log_warning(class, preload)("Preloading class %s during linking of class %s (cause: LoadableDescriptors attribute) but loaded class is not a value class", class_name->as_C_string(), name()->as_C_string());
+           }
+         } else {
+           log_warning(class, preload)("Preloading of class %s during linking of class %s (cause: LoadableDescriptors attribute) failed", class_name->as_C_string(), name()->as_C_string());
+         }
+       }
+     }
+   }
+ 
    // in case the class is linked in the process of linking its superclasses
    if (is_linked()) {
      return true;
    }
  

*** 1162,10 ***
--- 1338,45 ---
                                 jt->name(), external_name());
        }
      }
    }
  
+   // Pre-allocating an instance of the default value
+   if (is_inline_klass()) {
+       InlineKlass* vk = InlineKlass::cast(this);
+       oop val = vk->allocate_instance(THREAD);
+       if (HAS_PENDING_EXCEPTION) {
+           Handle e(THREAD, PENDING_EXCEPTION);
+           CLEAR_PENDING_EXCEPTION;
+           {
+               EXCEPTION_MARK;
+               add_initialization_error(THREAD, e);
+               // Locks object, set state, and notify all waiting threads
+               set_initialization_state_and_notify(initialization_error, THREAD);
+               CLEAR_PENDING_EXCEPTION;
+           }
+           THROW_OOP(e());
+       }
+       vk->set_default_value(val);
+       if (vk->has_nullable_layout()) {
+         val = vk->allocate_instance(THREAD);
+         if (HAS_PENDING_EXCEPTION) {
+             Handle e(THREAD, PENDING_EXCEPTION);
+             CLEAR_PENDING_EXCEPTION;
+             {
+                 EXCEPTION_MARK;
+                 add_initialization_error(THREAD, e);
+                 // Locks object, set state, and notify all waiting threads
+                 set_initialization_state_and_notify(initialization_error, THREAD);
+                 CLEAR_PENDING_EXCEPTION;
+             }
+             THROW_OOP(e());
+         }
+         vk->set_null_reset_value(val);
+       }
+   }
+ 
    // Step 7
    // Next, if C is a class rather than an interface, initialize it's super class and super
    // interfaces.
    if (!is_interface()) {
      Klass* super_klass = super();

*** 1194,12 ***
        DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
        THROW_OOP(e());
      }
    }
  
- 
    // Step 8
    {
      DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
      if (class_initializer() != nullptr) {
        // Timer includes any side effects of class initialization (resolution,
        // etc), but not recursive entry into call_class_initializer().
--- 1405,44 ---
        DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
        THROW_OOP(e());
      }
    }
  
    // Step 8
+   // Initialize classes of inline fields
+   if (EnableValhalla) {
+     for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+       if (fs.is_null_free_inline_type()) {
+ 
+         // inline type field klass array entries must have alreadyt been filed at load time or link time
+         Klass* klass = get_inline_type_field_klass(fs.index());
+ 
+         InstanceKlass::cast(klass)->initialize(THREAD);
+         if (fs.access_flags().is_static()) {
+           if (java_mirror()->obj_field(fs.offset()) == nullptr) {
+             java_mirror()->obj_field_put(fs.offset(), InlineKlass::cast(klass)->default_value());
+           }
+         }
+ 
+         if (HAS_PENDING_EXCEPTION) {
+           Handle e(THREAD, PENDING_EXCEPTION);
+           CLEAR_PENDING_EXCEPTION;
+           {
+             EXCEPTION_MARK;
+             add_initialization_error(THREAD, e);
+             // Locks object, set state, and notify all waiting threads
+             set_initialization_state_and_notify(initialization_error, THREAD);
+             CLEAR_PENDING_EXCEPTION;
+           }
+           THROW_OOP(e());
+         }
+       }
+     }
+   }
+ 
+ 
+   // Step 9
    {
      DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
      if (class_initializer() != nullptr) {
        // Timer includes any side effects of class initialization (resolution,
        // etc), but not recursive entry into call_class_initializer().

*** 1217,17 ***
        }
        call_class_initializer(THREAD);
      }
    }
  
!   // Step 9
    if (!HAS_PENDING_EXCEPTION) {
      set_initialization_state_and_notify(fully_initialized, CHECK);
      debug_only(vtable().verify(tty, true);)
    }
    else {
!     // Step 10 and 11
      Handle e(THREAD, PENDING_EXCEPTION);
      CLEAR_PENDING_EXCEPTION;
      // JVMTI has already reported the pending exception
      // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
      JvmtiExport::clear_detected_exception(jt);
--- 1460,17 ---
        }
        call_class_initializer(THREAD);
      }
    }
  
!   // Step 10
    if (!HAS_PENDING_EXCEPTION) {
      set_initialization_state_and_notify(fully_initialized, CHECK);
      debug_only(vtable().verify(tty, true);)
    }
    else {
!     // Step 11 and 12
      Handle e(THREAD, PENDING_EXCEPTION);
      CLEAR_PENDING_EXCEPTION;
      // JVMTI has already reported the pending exception
      // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
      JvmtiExport::clear_detected_exception(jt);

*** 1528,29 ***
      // Recursively lock array allocation
      RecursiveLocker rl(MultiArray_lock, THREAD);
  
      // Check if another thread created the array klass while we were waiting for the lock.
      if (array_klasses() == nullptr) {
!       ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, CHECK_NULL);
        // use 'release' to pair with lock-free load
        release_set_array_klasses(k);
      }
    }
  
    // array_klasses() will always be set at this point
!   ObjArrayKlass* ak = array_klasses();
    assert(ak != nullptr, "should be set");
    return ak->array_klass(n, THREAD);
  }
  
  ArrayKlass* InstanceKlass::array_klass_or_null(int n) {
    // Need load-acquire for lock-free read
!   ObjArrayKlass* oak = array_klasses_acquire();
!   if (oak == nullptr) {
      return nullptr;
    } else {
!     return oak->array_klass_or_null(n);
    }
  }
  
  ArrayKlass* InstanceKlass::array_klass(TRAPS) {
    return array_klass(1, THREAD);
--- 1771,29 ---
      // Recursively lock array allocation
      RecursiveLocker rl(MultiArray_lock, THREAD);
  
      // Check if another thread created the array klass while we were waiting for the lock.
      if (array_klasses() == nullptr) {
!       ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, false, CHECK_NULL);
        // use 'release' to pair with lock-free load
        release_set_array_klasses(k);
      }
    }
  
    // array_klasses() will always be set at this point
!   ArrayKlass* ak = array_klasses();
    assert(ak != nullptr, "should be set");
    return ak->array_klass(n, THREAD);
  }
  
  ArrayKlass* InstanceKlass::array_klass_or_null(int n) {
    // Need load-acquire for lock-free read
!   ArrayKlass* ak = array_klasses_acquire();
!   if (ak == nullptr) {
      return nullptr;
    } else {
!     return ak->array_klass_or_null(n);
    }
  }
  
  ArrayKlass* InstanceKlass::array_klass(TRAPS) {
    return array_klass(1, THREAD);

*** 1563,11 ***
  static int call_class_initializer_counter = 0;   // for debugging
  
  Method* InstanceKlass::class_initializer() const {
    Method* clinit = find_method(
        vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
!   if (clinit != nullptr && clinit->has_valid_initializer_flags()) {
      return clinit;
    }
    return nullptr;
  }
  
--- 1806,11 ---
  static int call_class_initializer_counter = 0;   // for debugging
  
  Method* InstanceKlass::class_initializer() const {
    Method* clinit = find_method(
        vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
!   if (clinit != nullptr && clinit->is_class_initializer()) {
      return clinit;
    }
    return nullptr;
  }
  

*** 1627,14 ***
    }
    // _oop_map_cache is constant after init; lookup below does its own locking.
    oop_map_cache->lookup(method, bci, entry_for);
  }
  
- bool InstanceKlass::contains_field_offset(int offset) {
-   fieldDescriptor fd;
-   return find_field_from_offset(offset, false, &fd);
- }
  
  FieldInfo InstanceKlass::field(int index) const {
    for (AllFieldStream fs(this); !fs.done(); fs.next()) {
      if (fs.index() == index) {
        return fs.to_FieldInfo();
--- 1870,10 ---

*** 1712,10 ***
--- 1951,19 ---
    }
    // 4) otherwise field lookup fails
    return nullptr;
  }
  
+ bool InstanceKlass::contains_field_offset(int offset) {
+   if (this->is_inline_klass()) {
+     InlineKlass* vk = InlineKlass::cast(this);
+     return offset >= vk->first_field_offset() && offset < (vk->first_field_offset() + vk->payload_size_in_bytes());
+   } else {
+     fieldDescriptor fd;
+     return find_field_from_offset(offset, false, &fd);
+   }
+ }
  
  bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
    for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
      if (fs.offset() == offset) {
        fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());

*** 2103,10 ***
--- 2351,13 ---
                                                                          StaticLookupMode::find,
                                                                          private_mode);
      if (method != nullptr) {
        return method;
      }
+     if (name == vmSymbols::object_initializer_name()) {
+       break;  // <init> is never inherited
+     }
      klass = klass->super();
      overpass_local_mode = OverpassLookupMode::skip;   // Always ignore overpass methods in superclasses
    }
    return nullptr;
  }

*** 2499,11 ***
--- 2750,13 ---
      }
    }
  
    it->push(&_nest_members);
    it->push(&_permitted_subclasses);
+   it->push(&_loadable_descriptors);
    it->push(&_record_components);
+   it->push(&_inline_layout_info_array, MetaspaceClosure::_writable);
  }
  
  #if INCLUDE_CDS
  void InstanceKlass::remove_unshareable_info() {
  

*** 2545,11 ***
    // do array classes also.
    if (array_klasses() != nullptr) {
      array_klasses()->remove_unshareable_info();
    }
  
!   // These are not allocated from metaspace. They are safe to set to null.
    _source_debug_extension = nullptr;
    _dep_context = nullptr;
    _osr_nmethods_head = nullptr;
  #if INCLUDE_JVMTI
    _breakpoints = nullptr;
--- 2798,11 ---
    // do array classes also.
    if (array_klasses() != nullptr) {
      array_klasses()->remove_unshareable_info();
    }
  
!   // These are not allocated from metaspace. They are safe to set to nullptr.
    _source_debug_extension = nullptr;
    _dep_context = nullptr;
    _osr_nmethods_head = nullptr;
  #if INCLUDE_JVMTI
    _breakpoints = nullptr;

*** 2629,10 ***
--- 2882,14 ---
    assert(!is_loaded(), "invalid init state");
    assert(!shared_loading_failed(), "Must not try to load failed class again");
    set_package(loader_data, pkg_entry, CHECK);
    Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
  
+   if (is_inline_klass()) {
+     InlineKlass::cast(this)->initialize_calling_convention(CHECK);
+   }
+ 
    Array<Method*>* methods = this->methods();
    int num_methods = methods->length();
    for (int index = 0; index < num_methods; ++index) {
      methods->at(index)->restore_unshareable_info(CHECK);
    }

*** 2657,11 ***
  
    if (array_klasses() != nullptr) {
      // To get a consistent list of classes we need MultiArray_lock to ensure
      // array classes aren't observed while they are being restored.
      RecursiveLocker rl(MultiArray_lock, THREAD);
!     assert(this == array_klasses()->bottom_klass(), "sanity");
      // Array classes have null protection domain.
      // --> see ArrayKlass::complete_create_array_klass()
      array_klasses()->restore_unshareable_info(class_loader_data(), Handle(), CHECK);
    }
  
--- 2914,11 ---
  
    if (array_klasses() != nullptr) {
      // To get a consistent list of classes we need MultiArray_lock to ensure
      // array classes aren't observed while they are being restored.
      RecursiveLocker rl(MultiArray_lock, THREAD);
!     assert(this == ObjArrayKlass::cast(array_klasses())->bottom_klass(), "sanity");
      // Array classes have null protection domain.
      // --> see ArrayKlass::complete_create_array_klass()
      array_klasses()->restore_unshareable_info(class_loader_data(), Handle(), CHECK);
    }
  

*** 2857,20 ***
  Symbol* InstanceKlass::generic_signature() const                   { return _constants->generic_signature(); }
  u2 InstanceKlass::generic_signature_index() const                  { return _constants->generic_signature_index(); }
  void InstanceKlass::set_generic_signature_index(u2 sig_index)      { _constants->set_generic_signature_index(sig_index); }
  
  const char* InstanceKlass::signature_name() const {
  
    // Get the internal name as a c string
    const char* src = (const char*) (name()->as_C_string());
    const int src_length = (int)strlen(src);
  
    char* dest = NEW_RESOURCE_ARRAY(char, src_length + 3);
  
!   // Add L as type indicator
    int dest_index = 0;
!   dest[dest_index++] = JVM_SIGNATURE_CLASS;
  
    // Add the actual class name
    for (int src_index = 0; src_index < src_length; ) {
      dest[dest_index++] = src[src_index++];
    }
--- 3114,23 ---
  Symbol* InstanceKlass::generic_signature() const                   { return _constants->generic_signature(); }
  u2 InstanceKlass::generic_signature_index() const                  { return _constants->generic_signature_index(); }
  void InstanceKlass::set_generic_signature_index(u2 sig_index)      { _constants->set_generic_signature_index(sig_index); }
  
  const char* InstanceKlass::signature_name() const {
+   return signature_name_of_carrier(JVM_SIGNATURE_CLASS);
+ }
  
+ const char* InstanceKlass::signature_name_of_carrier(char c) const {
    // Get the internal name as a c string
    const char* src = (const char*) (name()->as_C_string());
    const int src_length = (int)strlen(src);
  
    char* dest = NEW_RESOURCE_ARRAY(char, src_length + 3);
  
!   // Add L or Q as type indicator
    int dest_index = 0;
!   dest[dest_index++] = c;
  
    // Add the actual class name
    for (int src_index = 0; src_index < src_length; ) {
      dest[dest_index++] = src[src_index++];
    }

*** 3208,12 ***
        // This is really a member class.
        access = iter.inner_access_flags();
        break;
      }
    }
!   // Remember to strip ACC_SUPER bit
-   return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS;
  }
  
  jint InstanceKlass::jvmti_class_status() const {
    jint result = 0;
  
--- 3468,11 ---
        // This is really a member class.
        access = iter.inner_access_flags();
        break;
      }
    }
!   return (access & JVM_ACC_WRITTEN_FLAGS);
  }
  
  jint InstanceKlass::jvmti_class_status() const {
    jint result = 0;
  

*** 3463,24 ***
  
  static const char* state_names[] = {
    "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
  };
  
! static void print_vtable(intptr_t* start, int len, outputStream* st) {
    for (int i = 0; i < len; i++) {
      intptr_t e = start[i];
      st->print("%d : " INTPTR_FORMAT, i, e);
      if (MetaspaceObj::is_valid((Metadata*)e)) {
        st->print(" ");
        ((Metadata*)e)->print_value_on(st);
      }
      st->cr();
    }
  }
  
  static void print_vtable(vtableEntry* start, int len, outputStream* st) {
!   return print_vtable(reinterpret_cast<intptr_t*>(start), len, st);
  }
  
  const char* InstanceKlass::init_state_name() const {
    return state_names[init_state()];
  }
--- 3722,59 ---
  
  static const char* state_names[] = {
    "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
  };
  
! static void print_vtable(address self, intptr_t* start, int len, outputStream* st) {
+   ResourceMark rm;
+   int* forward_refs = NEW_RESOURCE_ARRAY(int, len);
+   for (int i = 0; i < len; i++)  forward_refs[i] = 0;
    for (int i = 0; i < len; i++) {
      intptr_t e = start[i];
      st->print("%d : " INTPTR_FORMAT, i, e);
+     if (forward_refs[i] != 0) {
+       int from = forward_refs[i];
+       int off = (int) start[from];
+       st->print(" (offset %d <= [%d])", off, from);
+     }
      if (MetaspaceObj::is_valid((Metadata*)e)) {
        st->print(" ");
        ((Metadata*)e)->print_value_on(st);
+     } else if (self != nullptr && e > 0 && e < 0x10000) {
+       address location = self + e;
+       int index = (int)((intptr_t*)location - start);
+       st->print(" (offset %d => [%d])", (int)e, index);
+       if (index >= 0 && index < len)
+         forward_refs[index] = i;
      }
      st->cr();
    }
  }
  
  static void print_vtable(vtableEntry* start, int len, outputStream* st) {
!   return print_vtable(nullptr, reinterpret_cast<intptr_t*>(start), len, st);
+ }
+ 
+ template<typename T>
+  static void print_array_on(outputStream* st, Array<T>* array) {
+    if (array == nullptr) { st->print_cr("nullptr"); return; }
+    array->print_value_on(st); st->cr();
+    if (Verbose || WizardMode) {
+      for (int i = 0; i < array->length(); i++) {
+        st->print("%d : ", i); array->at(i)->print_value_on(st); st->cr();
+      }
+    }
+  }
+ 
+ static void print_array_on(outputStream* st, Array<int>* array) {
+   if (array == nullptr) { st->print_cr("nullptr"); return; }
+   array->print_value_on(st); st->cr();
+   if (Verbose || WizardMode) {
+     for (int i = 0; i < array->length(); i++) {
+       st->print("%d : %d", i, array->at(i)); st->cr();
+     }
+   }
  }
  
  const char* InstanceKlass::init_state_name() const {
    return state_names[init_state()];
  }

*** 3517,26 ***
        st->cr();
      }
    }
  
    st->print(BULLET"arrays:            "); Metadata::print_value_on_maybe_null(st, array_klasses()); st->cr();
!   st->print(BULLET"methods:           "); methods()->print_value_on(st);               st->cr();
!   if (Verbose || WizardMode) {
-     Array<Method*>* method_array = methods();
-     for (int i = 0; i < method_array->length(); i++) {
-       st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-     }
-   }
-   st->print(BULLET"method ordering:   "); method_ordering()->print_value_on(st);      st->cr();
    if (default_methods() != nullptr) {
!     st->print(BULLET"default_methods:   "); default_methods()->print_value_on(st);    st->cr();
-     if (Verbose) {
-       Array<Method*>* method_array = default_methods();
-       for (int i = 0; i < method_array->length(); i++) {
-         st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-       }
-     }
    }
    print_on_maybe_null(st, BULLET"default vtable indices:   ", default_vtable_indices());
    st->print(BULLET"local interfaces:  "); local_interfaces()->print_value_on(st);      st->cr();
    st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr();
  
--- 3811,14 ---
        st->cr();
      }
    }
  
    st->print(BULLET"arrays:            "); Metadata::print_value_on_maybe_null(st, array_klasses()); st->cr();
!   st->print(BULLET"methods:           "); print_array_on(st, methods());
!   st->print(BULLET"method ordering:   "); print_array_on(st, method_ordering());
    if (default_methods() != nullptr) {
!     st->print(BULLET"default_methods:   "); print_array_on(st, default_methods());
    }
    print_on_maybe_null(st, BULLET"default vtable indices:   ", default_vtable_indices());
    st->print(BULLET"local interfaces:  "); local_interfaces()->print_value_on(st);      st->cr();
    st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr();
  

*** 3592,21 ***
    print_on_maybe_null(st, BULLET"generic signature: ", generic_signature());
    st->print(BULLET"inner classes:     "); inner_classes()->print_value_on(st);     st->cr();
    st->print(BULLET"nest members:     "); nest_members()->print_value_on(st);     st->cr();
    print_on_maybe_null(st, BULLET"record components:     ", record_components());
    st->print(BULLET"permitted subclasses:     "); permitted_subclasses()->print_value_on(st);     st->cr();
    if (java_mirror() != nullptr) {
      st->print(BULLET"java mirror:       ");
      java_mirror()->print_value_on(st);
      st->cr();
    } else {
      st->print_cr(BULLET"java mirror:       null");
    }
    st->print(BULLET"vtable length      %d  (start addr: " PTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr();
    if (vtable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_vtable(), vtable_length(), st);
    st->print(BULLET"itable length      %d (start addr: " PTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr();
!   if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_itable(), itable_length(), st);
    st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
  
    FieldPrinter print_static_field(st);
    ((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
    st->print_cr(BULLET"---- non-static fields (%d words):", nonstatic_field_size());
--- 3874,22 ---
    print_on_maybe_null(st, BULLET"generic signature: ", generic_signature());
    st->print(BULLET"inner classes:     "); inner_classes()->print_value_on(st);     st->cr();
    st->print(BULLET"nest members:     "); nest_members()->print_value_on(st);     st->cr();
    print_on_maybe_null(st, BULLET"record components:     ", record_components());
    st->print(BULLET"permitted subclasses:     "); permitted_subclasses()->print_value_on(st);     st->cr();
+   st->print(BULLET"loadable descriptors:     "); loadable_descriptors()->print_value_on(st); st->cr();
    if (java_mirror() != nullptr) {
      st->print(BULLET"java mirror:       ");
      java_mirror()->print_value_on(st);
      st->cr();
    } else {
      st->print_cr(BULLET"java mirror:       null");
    }
    st->print(BULLET"vtable length      %d  (start addr: " PTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr();
    if (vtable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_vtable(), vtable_length(), st);
    st->print(BULLET"itable length      %d (start addr: " PTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr();
!   if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(nullptr, start_of_itable(), itable_length(), st);
    st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
  
    FieldPrinter print_static_field(st);
    ((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
    st->print_cr(BULLET"---- non-static fields (%d words):", nonstatic_field_size());
< prev index next >