< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page
*** 63,10 ***
--- 63,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/atomic.hpp"

*** 153,10 ***
--- 154,12 ---
      }
    }
    return false;
  }
  
+ bool InstanceKlass::field_is_inline_type(int index) const { return Signature::basic_type(field(index)->signature(constants())) == T_INLINE_TYPE; }
+ 
  // private: called to verify that k is a static member of this nest.
  // We know that k is an instance class in the same package and hence the
  // same classloader.
  bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
    assert(!is_hidden(), "unexpected hidden class");

*** 471,11 ***
    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_unsafe_anonymous(),
!                                        should_store_fingerprint(is_hidden_or_anonymous));
  
    const Symbol* const class_name = parser.class_name();
    assert(class_name != NULL, "invariant");
    ClassLoaderData* loader_data = parser.loader_data();
    assert(loader_data != NULL, "invariant");
--- 474,13 ---
    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_unsafe_anonymous(),
!                                        should_store_fingerprint(is_hidden_or_anonymous),
+                                        parser.has_inline_fields() ? parser.java_fields_count() : 0,
+                                        parser.is_inline_type());
  
    const Symbol* const class_name = parser.class_name();
    assert(class_name != NULL, "invariant");
    ClassLoaderData* loader_data = parser.loader_data();
    assert(loader_data != NULL, "invariant");

*** 485,14 ***
    // Allocation
    if (REF_NONE == parser.reference_type()) {
      if (class_name == vmSymbols::java_lang_Class()) {
        // mirror
        ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
!     }
-     else if (is_class_loader(class_name, parser)) {
        // class loader
        ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
      } else {
        // normal
        ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_kind_other);
      }
    } else {
--- 490,16 ---
    // Allocation
    if (REF_NONE == parser.reference_type()) {
      if (class_name == vmSymbols::java_lang_Class()) {
        // mirror
        ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
!     } else if (is_class_loader(class_name, parser)) {
        // class loader
        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, InstanceKlass::_kind_other);
      }
    } else {

*** 504,13 ***
--- 511,43 ---
    // class count.  Can get OOM here.
    if (HAS_PENDING_EXCEPTION) {
      return NULL;
    }
  
+ #ifdef ASSERT
+   assert(ik->size() == size, "");
+   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 = NULL;
+   address end = NULL;
+   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 != NULL) {
      // allocate a new array and copy contents (memcpy?)

*** 541,29 ***
    _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(parser.reference_type()),
!   _init_thread(NULL)
  {
    set_vtable_length(parser.vtable_size());
    set_kind(kind);
    set_access_flags(parser.access_flags());
    if (parser.is_hidden()) set_is_hidden();
    set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
    set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                      false));
  
!   assert(NULL == _methods, "underlying memory not zeroed?");
!   assert(is_instance_klass(), "is layout incorrect?");
!   assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
  
    // Set biased locking bit for all instances of this class; it will be
    // cleared if revocation occurs too often for this type
    if (UseBiasedLocking && BiasedLocking::enabled()) {
      set_prototype_header(markWord::biased_locking_prototype());
    }
  }
  
  void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
                                         Array<Method*>* methods) {
    if (methods != NULL && methods != Universe::the_empty_method_array() &&
--- 578,38 ---
    _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(parser.reference_type()),
!   _init_thread(NULL),
+   _inline_type_field_klasses(NULL),
+   _adr_inlineklass_fixed_block(NULL)
  {
    set_vtable_length(parser.vtable_size());
    set_kind(kind);
    set_access_flags(parser.access_flags());
    if (parser.is_hidden()) set_is_hidden();
    set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
    set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                      false));
+     if (parser.has_inline_fields()) {
+       set_has_inline_type_fields();
+     }
+     _java_fields_count = parser.java_fields_count();
  
!     assert(NULL == _methods, "underlying memory not zeroed?");
!     assert(is_instance_klass(), "is layout incorrect?");
!     assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
  
    // Set biased locking bit for all instances of this class; it will be
    // cleared if revocation occurs too often for this type
    if (UseBiasedLocking && BiasedLocking::enabled()) {
      set_prototype_header(markWord::biased_locking_prototype());
    }
+   if (has_inline_type_fields()) {
+     _inline_type_field_klasses = (const Klass**) adr_inline_type_field_klasses();
+   }
  }
  
  void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
                                         Array<Method*>* methods) {
    if (methods != NULL && methods != Universe::the_empty_method_array() &&

*** 589,18 ***
    Array<InstanceKlass*>* ti = transitive_interfaces;
    if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) {
      // check that the interfaces don't come from super class
      Array<InstanceKlass*>* sti = (super_klass == NULL) ? NULL :
                      InstanceKlass::cast(super_klass)->transitive_interfaces();
!     if (ti != sti && ti != NULL && !ti->is_shared()) {
        MetadataFactory::free_array<InstanceKlass*>(loader_data, ti);
      }
    }
  
    // local interfaces can be empty
    if (local_interfaces != Universe::the_empty_instance_klass_array() &&
!       local_interfaces != NULL && !local_interfaces->is_shared()) {
      MetadataFactory::free_array<InstanceKlass*>(loader_data, local_interfaces);
    }
  }
  
  void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
--- 635,20 ---
    Array<InstanceKlass*>* ti = transitive_interfaces;
    if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) {
      // check that the interfaces don't come from super class
      Array<InstanceKlass*>* sti = (super_klass == NULL) ? NULL :
                      InstanceKlass::cast(super_klass)->transitive_interfaces();
!     if (ti != sti && ti != NULL && !ti->is_shared() &&
+         ti != Universe::the_single_IdentityObject_klass_array()) {
        MetadataFactory::free_array<InstanceKlass*>(loader_data, ti);
      }
    }
  
    // local interfaces can be empty
    if (local_interfaces != Universe::the_empty_instance_klass_array() &&
!       local_interfaces != NULL && !local_interfaces->is_shared() &&
+       local_interfaces != Universe::the_single_IdentityObject_klass_array()) {
      MetadataFactory::free_array<InstanceKlass*>(loader_data, local_interfaces);
    }
  }
  
  void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,

*** 924,10 ***
--- 972,66 ---
    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?
+   {
+     ResourceMark rm(THREAD);
+     for (int i = 0; i < methods()->length(); i++) {
+       Method* m = methods()->at(i);
+       for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) {
+         if (ss.is_reference()) {
+           if (ss.is_array()) {
+             ss.skip_array_prefix();
+           }
+           if (ss.type() == T_INLINE_TYPE) {
+             Symbol* symb = ss.as_symbol();
+ 
+             oop loader = class_loader();
+             oop protection_domain = this->protection_domain();
+             Klass* klass = SystemDictionary::resolve_or_fail(symb,
+                                                              Handle(THREAD, loader), Handle(THREAD, protection_domain), true,
+                                                              CHECK_false);
+             if (klass == NULL) {
+               THROW_(vmSymbols::java_lang_LinkageError(), false);
+             }
+             if (!klass->is_inline_klass()) {
+               Exceptions::fthrow(
+                 THREAD_AND_LOCATION,
+                 vmSymbols::java_lang_IncompatibleClassChangeError(),
+                 "class %s is not an inline type",
+                 klass->external_name());
+             }
+           }
+         }
+       }
+     }
+   }
+ 
    // in case the class is linked in the process of linking its superclasses
    if (is_linked()) {
      return true;
    }
  

*** 995,10 ***
--- 1099,11 ---
  #ifdef ASSERT
        vtable().verify(tty, true);
        // In case itable verification is ever added.
        // itable().verify(tty, true);
  #endif
+ 
        set_init_state(linked);
        if (JvmtiExport::should_post_class_prepare()) {
          Thread *thread = THREAD;
          assert(thread->is_Java_thread(), "thread->is_Java_thread()");
          JvmtiExport::post_class_prepare((JavaThread *) thread, this);

*** 1148,15 ***
        DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
        THROW_OOP(e());
      }
    }
  
  
    // Look for aot compiled methods for this klass, including class initializer.
    AOTLoader::load_for_klass(this, THREAD);
  
!   // Step 8
    {
      DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
      if (class_initializer() != NULL) {
        // Timer includes any side effects of class initialization (resolution,
        // etc), but not recursive entry into call_class_initializer().
--- 1253,44 ---
        DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
        THROW_OOP(e());
      }
    }
  
+   // Step 8
+   // Initialize classes of inline fields
+   {
+     for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+       if (Signature::basic_type(fs.signature()) == T_INLINE_TYPE) {
+         Klass* klass = get_inline_type_field_klass_or_null(fs.index());
+         if (fs.access_flags().is_static() && klass == NULL) {
+           klass = SystemDictionary::resolve_or_fail(field_signature(fs.index())->fundamental_name(THREAD),
+               Handle(THREAD, class_loader()),
+               Handle(THREAD, protection_domain()),
+               true, CHECK);
+           if (klass == NULL) {
+             THROW(vmSymbols::java_lang_NoClassDefFoundError());
+           }
+           if (!klass->is_inline_klass()) {
+             THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
+           }
+           set_inline_type_field_klass(fs.index(), klass);
+         }
+         InstanceKlass::cast(klass)->initialize(CHECK);
+         if (fs.access_flags().is_static()) {
+           if (java_mirror()->obj_field(fs.offset()) == NULL) {
+             java_mirror()->obj_field_put(fs.offset(), InlineKlass::cast(klass)->default_value());
+           }
+         }
+       }
+     }
+   }
+ 
  
    // Look for aot compiled methods for this klass, including class initializer.
    AOTLoader::load_for_klass(this, THREAD);
  
!   // Step 9
    {
      DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
      if (class_initializer() != NULL) {
        // Timer includes any side effects of class initialization (resolution,
        // etc), but not recursive entry into call_class_initializer().

*** 1174,19 ***
        }
        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);
--- 1308,19 ---
        }
        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);

*** 1470,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 != NULL && clinit->has_valid_initializer_flags()) {
      return clinit;
    }
    return NULL;
  }
  
--- 1604,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 != NULL && clinit->is_class_initializer()) {
      return clinit;
    }
    return NULL;
  }
  

*** 1508,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 == NULL) {
!     MutexLocker x(OopMapCacheAlloc_lock);
      // Check if _oop_map_cache was allocated while we were waiting for this lock
      if ((oop_map_cache = _oop_map_cache) == NULL) {
        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);
--- 1642,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 == NULL) {
!     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) == NULL) {
        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);

*** 1520,15 ***
    }
    // _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);
- }
- 
  bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
    for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
      Symbol* f_name = fs.name();
      Symbol* f_sig  = fs.signature();
      if (f_name == name && f_sig == sig) {
--- 1654,10 ---

*** 1595,10 ***
--- 1724,19 ---
    }
    // 4) otherwise field lookup fails
    return NULL;
  }
  
+ 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_exact_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());

*** 1979,10 ***
--- 2117,13 ---
                                                                          find_static,
                                                                          private_mode);
      if (method != NULL) {
        return method;
      }
+     if (name == vmSymbols::object_initializer_name()) {
+       break;  // <init> is never inherited, not even as a static factory
+     }
      klass = klass->super();
      overpass_local_mode = skip_overpass;   // Always ignore overpass methods in superclasses
    }
    return NULL;
  }

*** 2487,10 ***
--- 2628,16 ---
    }
  
    it->push(&_nest_members);
    it->push(&_permitted_subclasses);
    it->push(&_record_components);
+ 
+   if (has_inline_type_fields()) {
+     for (int i = 0; i < java_fields_count(); i++) {
+       it->push(&((Klass**)adr_inline_type_field_klasses())[i]);
+     }
+   }
  }
  
  void InstanceKlass::remove_unshareable_info() {
    Klass::remove_unshareable_info();
  

*** 2522,10 ***
--- 2669,18 ---
    // do array classes also.
    if (array_klasses() != NULL) {
      array_klasses()->remove_unshareable_info();
    }
  
+   if (has_inline_type_fields()) {
+     for (AllFieldStream fs(fields(), constants()); !fs.done(); fs.next()) {
+       if (Signature::basic_type(fs.signature()) == T_INLINE_TYPE) {
+         reset_inline_type_field_klass(fs.index());
+       }
+     }
+   }
+ 
    // These are not allocated from metaspace. They are safe to set to NULL.
    _source_debug_extension = NULL;
    _dep_context = NULL;
    _osr_nmethods_head = NULL;
  #if INCLUDE_JVMTI

*** 2561,10 ***
--- 2716,14 ---
    // sure the current state is <loaded.
    assert(!is_loaded(), "invalid init state");
    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);
    }

*** 2586,11 ***
      // --> see ArrayKlass::complete_create_array_klass()
      array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
    }
  
    // Initialize current biased locking state.
!   if (UseBiasedLocking && BiasedLocking::enabled()) {
      set_prototype_header(markWord::biased_locking_prototype());
    }
  }
  
  void InstanceKlass::set_shared_class_loader_type(s2 loader_type) {
--- 2745,11 ---
      // --> see ArrayKlass::complete_create_array_klass()
      array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
    }
  
    // Initialize current biased locking state.
!   if (UseBiasedLocking && BiasedLocking::enabled() && !is_inline_klass()) {
      set_prototype_header(markWord::biased_locking_prototype());
    }
  }
  
  void InstanceKlass::set_shared_class_loader_type(s2 loader_type) {

*** 2751,13 ***
    const char* src = (const char*) (name()->as_C_string());
    const int src_length = (int)strlen(src);
  
    char* dest = NEW_RESOURCE_ARRAY(char, src_length + hash_len + 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++];
    }
--- 2910,13 ---
    const char* src = (const char*) (name()->as_C_string());
    const int src_length = (int)strlen(src);
  
    char* dest = NEW_RESOURCE_ARRAY(char, src_length + hash_len + 3);
  
!   // Add L or Q as type indicator
    int dest_index = 0;
!   dest[dest_index++] = is_inline_klass() ? JVM_SIGNATURE_INLINE_TYPE : JVM_SIGNATURE_CLASS;
  
    // Add the actual class name
    for (int src_index = 0; src_index < src_length; ) {
      dest[dest_index++] = src[src_index++];
    }

*** 3313,33 ***
  
  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);
  }
  
  void InstanceKlass::print_on(outputStream* st) const {
    assert(is_klass(), "must be klass");
    Klass::print_on(st);
  
    st->print(BULLET"instance size:     %d", size_helper());                        st->cr();
    st->print(BULLET"klass size:        %d", size());                               st->cr();
    st->print(BULLET"access:            "); access_flags().print_on(st);            st->cr();
    st->print(BULLET"state:             "); st->print_cr("%s", state_names[_init_state]);
    st->print(BULLET"name:              "); name()->print_value_on(st);             st->cr();
    st->print(BULLET"super:             "); Metadata::print_value_on_maybe_null(st, super()); st->cr();
    st->print(BULLET"sub:               ");
    Klass* sub = subklass();
--- 3472,69 ---
  
  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 != NULL && 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(NULL, reinterpret_cast<intptr_t*>(start), len, st);
+ }
+ 
+ template<typename T>
+  static void print_array_on(outputStream* st, Array<T>* array) {
+    if (array == NULL) { st->print_cr("NULL"); 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 == NULL) { st->print_cr("NULL"); 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();
+     }
+   }
  }
  
  void InstanceKlass::print_on(outputStream* st) const {
    assert(is_klass(), "must be klass");
    Klass::print_on(st);
  
    st->print(BULLET"instance size:     %d", size_helper());                        st->cr();
    st->print(BULLET"klass size:        %d", size());                               st->cr();
    st->print(BULLET"access:            "); access_flags().print_on(st);            st->cr();
+   st->print(BULLET"misc flags:        0x%x", _misc_flags);                        st->cr();
    st->print(BULLET"state:             "); st->print_cr("%s", state_names[_init_state]);
    st->print(BULLET"name:              "); name()->print_value_on(st);             st->cr();
    st->print(BULLET"super:             "); Metadata::print_value_on_maybe_null(st, super()); st->cr();
    st->print(BULLET"sub:               ");
    Klass* sub = subklass();

*** 3362,30 ***
        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() != NULL) {
-     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();
-     }
-   }
    if (default_vtable_indices() != NULL) {
!     st->print(BULLET"default vtable indices:   "); default_vtable_indices()->print_value_on(st);       st->cr();
    }
!   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"constants:         "); constants()->print_value_on(st);         st->cr();
    if (class_loader_data() != NULL) {
      st->print(BULLET"class loader data:  ");
      class_loader_data()->print_value_on(st);
      st->cr();
--- 3557,18 ---
        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());
!   st->print(BULLET"default_methods:   "); print_array_on(st, default_methods());
    if (default_vtable_indices() != NULL) {
!     st->print(BULLET"default vtable indices:   "); print_array_on(st, default_vtable_indices());
    }
!   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() != NULL) {
      st->print(BULLET"class loader data:  ");
      class_loader_data()->print_value_on(st);
      st->cr();

*** 3438,11 ***
      st->print_cr(BULLET"java mirror:       NULL");
    }
    st->print(BULLET"vtable length      %d  (start addr: " INTPTR_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: " INTPTR_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());
    FieldPrinter print_nonstatic_field(st);
--- 3621,11 ---
      st->print_cr(BULLET"java mirror:       NULL");
    }
    st->print(BULLET"vtable length      %d  (start addr: " INTPTR_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: " INTPTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr();
!   if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(NULL, 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);

*** 4174,5 ***
--- 4357,10 ---
  
  unsigned char * InstanceKlass::get_cached_class_file_bytes() {
    return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
  }
  #endif
+ 
+ #define THROW_DVT_ERROR(s) \
+   Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), \
+       "ValueCapableClass class '%s' %s", external_name(),(s)); \
+       return
< prev index next >