diff a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -69,10 +69,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"
@@ -165,10 +166,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->klass_at_noresolve(_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());
 }
@@ -437,11 +451,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_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");
@@ -459,10 +474,13 @@
     // stack chunk
     ik = new (loader_data, size, THREAD) InstanceStackChunkKlass(parser);
   } else if (is_class_loader(class_name, parser)) {
     // class loader - java.lang.ClassLoader
     ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
+  } else if (parser.is_inline_type()) {
+    // inline type
+    ik = new (loader_data, size, THREAD) InlineKlass(parser);
   } else {
     // normal
     ik = new (loader_data, size, THREAD) InstanceKlass(parser);
   }
 
@@ -470,13 +488,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?)
@@ -516,17 +563,24 @@
   _itable_len(parser.itable_size()),
   _nest_host_index(0),
   _init_state(allocated),
   _reference_type(reference_type),
   _init_monitor(create_init_monitor("InstanceKlassInitMonitor_lock")),
-  _init_thread(nullptr)
+  _init_thread(nullptr),
+  _inline_type_field_klasses(nullptr),
+  _null_marker_offsets(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?");
 }
@@ -662,10 +716,20 @@
   if (fields_status() != nullptr && !fields_status()->is_shared()) {
     MetadataFactory::free_array<FieldStatus>(loader_data, fields_status());
   }
   set_fields_status(nullptr);
 
+  if (inline_type_field_klasses_array() != nullptr) {
+    MetadataFactory::free_array<InlineKlass*>(loader_data, inline_type_field_klasses_array());
+    set_inline_type_field_klasses_array(nullptr);
+  }
+
+  if (null_marker_offsets_array() != nullptr) {
+    MetadataFactory::free_array<int>(loader_data, null_marker_offsets_array());
+    set_null_marker_offsets_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()) {
@@ -696,10 +760,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);
@@ -875,10 +946,111 @@
   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_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);
+          }
+          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);
+          }
+          InstanceKlass* ik = InstanceKlass::cast(klass);
+          if (!ik->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
+          if (inline_type_field_klasses_array()->at(fs.index()) == nullptr) {
+            set_inline_type_field_klass(fs.index(), InlineKlass::cast(ik));
+          }
+          assert(get_inline_type_field_klass(fs.index()) == ik, "Must match");
+        } else {
+          if (inline_type_field_klasses_array()->at(fs.index()) == nullptr) {
+            set_inline_type_field_klass(fs.index(), InlineKlass::cast(this));
+          }
+          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));
+        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;
   }
 
@@ -1164,10 +1336,29 @@
       THROW_MSG_CAUSE(vmSymbols::java_lang_NoClassDefFoundError(),
                       ss.as_string(), cause);
     }
   }
 
+  // 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);
+  }
+
   // 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();
@@ -1196,12 +1387,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().
@@ -1219,17 +1442,17 @@
       }
       call_class_initializer(THREAD);
     }
   }
 
-  // Step 9
+  // Step 10
   if (!HAS_PENDING_EXCEPTION) {
     set_initialization_state_and_notify(fully_initialized, THREAD);
     debug_only(vtable().verify(tty, true);)
   }
   else {
-    // Step 10 and 11
+    // 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);
@@ -1551,28 +1774,29 @@
       // Atomic creation of array_klasses
       MutexLocker ma(THREAD, MultiArray_lock);
 
       // Check if update has already taken place
       if (array_klasses() == nullptr) {
-        ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, CHECK_NULL);
+        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
-  ObjArrayKlass* oak = array_klasses();
-  return oak->array_klass(n, THREAD);
+  ArrayKlass* ak = array_klasses();
+  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) {
+  ArrayKlass* ak = array_klasses_acquire();
+  if (ak == nullptr) {
     return nullptr;
   } else {
-    return oak->array_klass_or_null(n);
+    return ak->array_klass_or_null(n);
   }
 }
 
 ArrayKlass* InstanceKlass::array_klass(TRAPS) {
   return array_klass(1, THREAD);
@@ -1585,11 +1809,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()) {
+  if (clinit != nullptr && clinit->is_class_initializer()) {
     return clinit;
   }
   return nullptr;
 }
 
@@ -1636,11 +1860,11 @@
   InterpreterOopMap* entry_for) {
   // Lazily create the _oop_map_cache at first request
   // Lock-free access requires load_acquire.
   OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache);
   if (oop_map_cache == nullptr) {
-    MutexLocker x(OopMapCacheAlloc_lock);
+    MutexLocker x(OopMapCacheAlloc_lock,  Mutex::_no_safepoint_check_flag);
     // Check if _oop_map_cache was allocated while we were waiting for this lock
     if ((oop_map_cache = _oop_map_cache) == nullptr) {
       oop_map_cache = new OopMapCache();
       // Ensure _oop_map_cache is stable, since it is examined without a lock
       Atomic::release_store(&_oop_map_cache, oop_map_cache);
@@ -1648,14 +1872,10 @@
   }
   // _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();
@@ -1733,10 +1953,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->get_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());
@@ -2124,10 +2353,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;
 }
@@ -2604,11 +2836,15 @@
     }
   }
 
   it->push(&_nest_members);
   it->push(&_permitted_subclasses);
+  it->push(&_loadable_descriptors);
   it->push(&_record_components);
+
+  it->push(&_inline_type_field_klasses, MetaspaceClosure::_writable);
+  it->push(&_null_marker_offsets);
 }
 
 #if INCLUDE_CDS
 void InstanceKlass::remove_unshareable_info() {
 
@@ -2648,11 +2884,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.
+  // 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;
@@ -2733,10 +2969,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);
   }
@@ -2761,11 +3001,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.
     MutexLocker ml(MultiArray_lock);
-    assert(this == array_klasses()->bottom_klass(), "sanity");
+    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);
   }
 
@@ -2960,20 +3200,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 as type indicator
+  // Add L or Q as type indicator
   int dest_index = 0;
-  dest[dest_index++] = JVM_SIGNATURE_CLASS;
+  dest[dest_index++] = c;
 
   // Add the actual class name
   for (int src_index = 0; src_index < src_length; ) {
     dest[dest_index++] = src[src_index++];
   }
@@ -3311,12 +3554,11 @@
       // 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;
+  return (access & JVM_ACC_WRITTEN_FLAGS);
 }
 
 jint InstanceKlass::jvmti_class_status() const {
   jint result = 0;
 
@@ -3566,24 +3808,59 @@
 
 static const char* state_names[] = {
   "allocated", "loaded", "being_linked", "linked", "being_initialized", "fully_initialized", "initialization_error"
 };
 
-static void print_vtable(intptr_t* start, int len, outputStream* st) {
+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(reinterpret_cast<intptr_t*>(start), len, 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()];
 }
@@ -3620,30 +3897,18 @@
       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();
-  st->print(BULLET"default_methods:   "); default_methods()->print_value_on(st);      st->cr();
-  if (Verbose && default_methods() != nullptr) {
-    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();
-    }
-  }
+  st->print(BULLET"methods:           "); print_array_on(st, methods());
+  st->print(BULLET"method ordering:   "); print_array_on(st, method_ordering());
+  st->print(BULLET"default_methods:   "); print_array_on(st, default_methods());
   if (default_vtable_indices() != nullptr) {
-    st->print(BULLET"default vtable indices:   "); default_vtable_indices()->print_value_on(st);       st->cr();
+    st->print(BULLET"default vtable indices:   "); print_array_on(st, 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();
+  st->print(BULLET"local interfaces:  "); print_array_on(st, local_interfaces());
+  st->print(BULLET"trans. interfaces: "); print_array_on(st, transitive_interfaces());
   st->print(BULLET"constants:         "); constants()->print_value_on(st);         st->cr();
   if (class_loader_data() != nullptr) {
     st->print(BULLET"class loader data:  ");
     class_loader_data()->print_value_on(st);
     st->cr();
@@ -3685,21 +3950,22 @@
   st->print(BULLET"nest members:     "); nest_members()->print_value_on(st);     st->cr();
   if (record_components() != nullptr) {
     st->print(BULLET"record components:     "); record_components()->print_value_on(st);     st->cr();
   }
   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(start_of_itable(), itable_length(), st);
+  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());
   FieldPrinter print_nonstatic_field(st);
