< prev index next >

src/share/vm/oops/constantPool.cpp

Print this page

*** 45,66 **** #include "runtime/signature.hpp" #include "runtime/vframe.hpp" #include "utilities/copy.hpp" ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { - // Tags are RW but comment below applies to tags also. Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL); - int size = ConstantPool::size(length); ! ! // CDS considerations: ! // Allocate read-write but may be able to move to read-only at dumping time ! // if all the klasses are resolved. The only other field that is writable is ! // the resolved_references array, which is recreated at startup time. ! // But that could be moved to InstanceKlass (although a pain to access from ! // assembly code). Maybe it could be moved to the cpCache which is RW. ! return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags); } #ifdef ASSERT // MetaspaceObj allocation invariant is calloc equivalent memory --- 45,57 ---- #include "runtime/signature.hpp" #include "runtime/vframe.hpp" #include "utilities/copy.hpp" ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) { Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL); int size = ConstantPool::size(length); ! return new (loader_data, size, true, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags); } #ifdef ASSERT // MetaspaceObj allocation invariant is calloc equivalent memory
*** 78,103 **** #endif ConstantPool::ConstantPool(Array<u1>* tags) : _tags(tags), ! _length(tags->length()), ! _flags(0) { assert(_tags != NULL, "invariant"); assert(tags->length() == _length, "invariant"); assert(tag_array_is_zero_initialized(tags), "invariant"); ! assert(0 == _flags, "invariant"); assert(0 == version(), "invariant"); assert(NULL == _pool_holder, "invariant"); } void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { ! MetadataFactory::free_metadata(loader_data, cache()); ! set_cache(NULL); MetadataFactory::free_array<u2>(loader_data, reference_map()); set_reference_map(NULL); MetadataFactory::free_array<jushort>(loader_data, operands()); set_operands(NULL); release_C_heap_structures(); --- 69,98 ---- #endif ConstantPool::ConstantPool(Array<u1>* tags) : _tags(tags), ! _length(tags->length()) { assert(_tags != NULL, "invariant"); assert(tags->length() == _length, "invariant"); assert(tag_array_is_zero_initialized(tags), "invariant"); ! assert(0 == flags(), "invariant"); assert(0 == version(), "invariant"); assert(NULL == _pool_holder, "invariant"); } void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { ! if (cache() != NULL) { MetadataFactory::free_array<u2>(loader_data, reference_map()); set_reference_map(NULL); + MetadataFactory::free_metadata(loader_data, cache()); + set_cache(NULL); + } + + MetadataFactory::free_array<Klass*>(loader_data, resolved_klasses()); + set_resolved_klasses(NULL); MetadataFactory::free_array<jushort>(loader_data, operands()); set_operands(NULL); release_C_heap_structures();
*** 111,121 **** // walk constant pool and decrement symbol reference counts unreference_symbols(); } objArrayOop ConstantPool::resolved_references() const { ! return (objArrayOop)JNIHandles::resolve(_resolved_references); } // Create resolved_references array and mapping array for original cp indexes // The ldc bytecode was rewritten to have the resolved reference array index so need a way // to map it back for resolving and some unlikely miscellaneous uses. --- 106,116 ---- // walk constant pool and decrement symbol reference counts unreference_symbols(); } objArrayOop ConstantPool::resolved_references() const { ! return (objArrayOop)JNIHandles::resolve(_cache->resolved_references()); } // Create resolved_references array and mapping array for original cp indexes // The ldc bytecode was rewritten to have the resolved reference array index so need a way // to map it back for resolving and some unlikely miscellaneous uses.
*** 148,160 **** --- 143,227 ---- Handle refs_handle (THREAD, (oop)stom); // must handleize. set_resolved_references(loader_data->add_handle(refs_handle)); } } + void ConstantPool::allocate_resolved_klasses(ClassLoaderData* loader_data, int num_klasses, TRAPS) { + // A ConstantPool can't possibly have 0xffff valid class entries, + // because entry #0 must be CONSTANT_Invalid, and each class entry must refer to a UTF8 + // entry for the class's name. So at most we will have 0xfffe class entries. + // This allows us to use 0xffff (ConstantPool::_temp_resolved_klass_index) to indicate + // UnresolvedKlass entries that are temporarily created during class redefinition. + assert(num_klasses < CPKlassSlot::_temp_resolved_klass_index, "sanity"); + assert(resolved_klasses() == NULL, "sanity"); + Array<Klass*>* rk = MetadataFactory::new_writeable_array<Klass*>(loader_data, num_klasses, CHECK); + set_resolved_klasses(rk); + } + + void ConstantPool::initialize_unresolved_klasses(ClassLoaderData* loader_data, TRAPS) { + int len = length(); + int num_klasses = 0; + for (int i = 1; i <len; i++) { + switch (tag_at(i).value()) { + case JVM_CONSTANT_ClassIndex: + { + const int class_index = klass_index_at(i); + unresolved_klass_at_put(i, class_index, num_klasses++); + } + break; + #ifndef PRODUCT + case JVM_CONSTANT_Class: + case JVM_CONSTANT_UnresolvedClass: + case JVM_CONSTANT_UnresolvedClassInError: + // All of these should have been reverted back to ClassIndex before calling + // this function. + ShouldNotReachHere(); + #endif + } + } + allocate_resolved_klasses(loader_data, num_klasses, THREAD); + } + + // Anonymous class support: + void ConstantPool::klass_at_put(int class_index, int name_index, int resolved_klass_index, Klass* k, Symbol* name) { + assert(is_within_bounds(class_index), "index out of bounds"); + assert(is_within_bounds(name_index), "index out of bounds"); + assert((resolved_klass_index & 0xffff0000) == 0, "must be"); + *int_at_addr(class_index) = + build_int_from_shorts((jushort)resolved_klass_index, (jushort)name_index); + + symbol_at_put(name_index, name); + name->increment_refcount(); + Klass** adr = resolved_klasses()->adr_at(resolved_klass_index); + OrderAccess::release_store_ptr((Klass* volatile *)adr, k); + + // The interpreter assumes when the tag is stored, the klass is resolved + // and the Klass* non-NULL, so we need hardware store ordering here. + if (k != NULL) { + release_tag_at_put(class_index, JVM_CONSTANT_Class); + } else { + release_tag_at_put(class_index, JVM_CONSTANT_UnresolvedClass); + } + } + + // Anonymous class support: + void ConstantPool::klass_at_put(int class_index, Klass* k) { + CPKlassSlot kslot = klass_slot_at(class_index); + int resolved_klass_index = kslot.resolved_klass_index(); + int name_index = kslot.name_index(); + Symbol* name = symbol_at(name_index); + guarantee(name == k->name(), "Invalid class name for anonymous"); + + Klass** adr = resolved_klasses()->adr_at(resolved_klass_index); + OrderAccess::release_store_ptr((Klass* volatile *)adr, k); + } + // CDS support. Create a new resolved_references array. void ConstantPool::restore_unshareable_info(TRAPS) { assert(is_constantPool(), "ensure C++ vtable is restored"); + assert(on_stack(), "should always be set for shared constant pools"); + assert(is_shared(), "should always be set for shared constant pools"); // Only create the new resolved references array if it hasn't been attempted before if (resolved_references() != NULL) return; // restore the C++ vtable from the shared archive
*** 178,187 **** --- 245,260 ---- // Save the length for restoration. It is not necessarily the same length // as reference_map.length() if invokedynamic is saved. set_resolved_reference_length( resolved_references() != NULL ? resolved_references()->length() : 0); set_resolved_references(NULL); + + // Shared ConstantPools are in the RO region, so the _flags cannot be modified. + // The _on_stack flag is used to prevent ConstantPools from deallocation during + // class redefinition. Since shared ConstantPools cannot be deallocated anyway, + // we always set _on_stack to true to avoid having to change _flags during runtime. + _flags |= (_on_stack | _is_shared); } int ConstantPool::cp_to_object_index(int cp_index) { // this is harder don't do this so much. int i = reference_map()->find(cp_index);
*** 227,241 **** assert(THREAD->is_Java_thread(), "must be a Java thread"); // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // It is not safe to rely on the tag bit's here, since we don't have a lock, and // the entry and tag is not updated atomicly. ! CPSlot entry = this_cp->slot_at(which); ! if (entry.is_resolved()) { ! assert(entry.get_klass()->is_klass(), "must be"); ! // Already resolved - return entry. ! return entry.get_klass(); } // This tag doesn't change back to unresolved class unless at a safepoint. if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { // The original attempt to resolve this constant pool entry failed so find the --- 300,317 ---- assert(THREAD->is_Java_thread(), "must be a Java thread"); // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. // It is not safe to rely on the tag bit's here, since we don't have a lock, and // the entry and tag is not updated atomicly. ! CPKlassSlot kslot = this_cp->klass_slot_at(which); ! int resolved_klass_index = kslot.resolved_klass_index(); ! int name_index = kslot.name_index(); ! assert(this_cp->tag_at(name_index).is_symbol(), "sanity"); ! ! Klass* klass = this_cp->resolved_klasses()->at(resolved_klass_index); ! if (klass != NULL) { ! return klass; } // This tag doesn't change back to unresolved class unless at a safepoint. if (this_cp->tag_at(which).is_unresolved_klass_in_error()) { // The original attempt to resolve this constant pool entry failed so find the
*** 249,259 **** throw_resolution_error(this_cp, which, CHECK_0); ShouldNotReachHere(); } Handle mirror_handle; ! Symbol* name = entry.get_symbol(); Handle loader (THREAD, this_cp->pool_holder()->class_loader()); Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain()); Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD); if (!HAS_PENDING_EXCEPTION) { // preserve the resolved klass from unloading --- 325,335 ---- throw_resolution_error(this_cp, which, CHECK_0); ShouldNotReachHere(); } Handle mirror_handle; ! Symbol* name = this_cp->symbol_at(name_index); Handle loader (THREAD, this_cp->pool_holder()->class_loader()); Handle protection_domain (THREAD, this_cp->pool_holder()->protection_domain()); Klass* k = SystemDictionary::resolve_or_fail(name, loader, protection_domain, true, THREAD); if (!HAS_PENDING_EXCEPTION) { // preserve the resolved klass from unloading
*** 268,281 **** if (save_resolution_error) { save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_NULL); // If CHECK_NULL above doesn't return the exception, that means that // some other thread has beaten us and has resolved the class. // To preserve old behavior, we return the resolved class. ! entry = this_cp->resolved_klass_at(which); ! assert(entry.is_resolved(), "must be resolved if exception was cleared"); ! assert(entry.get_klass()->is_klass(), "must be resolved to a klass"); ! return entry.get_klass(); } else { return NULL; // return the pending exception } } --- 344,356 ---- if (save_resolution_error) { save_and_throw_exception(this_cp, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_NULL); // If CHECK_NULL above doesn't return the exception, that means that // some other thread has beaten us and has resolved the class. // To preserve old behavior, we return the resolved class. ! klass = this_cp->resolved_klasses()->at(resolved_klass_index); ! assert(klass != NULL, "must be resolved if exception was cleared"); ! return klass; } else { return NULL; // return the pending exception } }
*** 285,314 **** // logging for class+resolve. if (log_is_enabled(Debug, class, resolve)){ trace_class_resolution(this_cp, k); } ! this_cp->klass_at_put(which, k); ! entry = this_cp->resolved_klass_at(which); ! assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point"); ! return entry.get_klass(); } // Does not update ConstantPool* - to avoid any exception throwing. Used // by compiler and exception handling. Also used to avoid classloads for // instanceof operations. Returns NULL if the class has not been loaded or // if the verification of constant pool failed Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) { ! CPSlot entry = this_cp->slot_at(which); ! if (entry.is_resolved()) { ! assert(entry.get_klass()->is_klass(), "must be"); ! return entry.get_klass(); } else { - assert(entry.is_unresolved(), "must be either symbol or klass"); Thread *thread = Thread::current(); ! Symbol* name = entry.get_symbol(); oop loader = this_cp->pool_holder()->class_loader(); oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (thread, protection_domain); Handle h_loader (thread, loader); Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread); --- 360,395 ---- // logging for class+resolve. if (log_is_enabled(Debug, class, resolve)){ trace_class_resolution(this_cp, k); } ! Klass** adr = this_cp->resolved_klasses()->adr_at(resolved_klass_index); ! OrderAccess::release_store_ptr((Klass* volatile *)adr, k); ! // The interpreter assumes when the tag is stored, the klass is resolved ! // and the Klass* stored in _resolved_klasses is non-NULL, so we need ! // hardware store ordering here. ! this_cp->release_tag_at_put(which, JVM_CONSTANT_Class); ! return k; } // Does not update ConstantPool* - to avoid any exception throwing. Used // by compiler and exception handling. Also used to avoid classloads for // instanceof operations. Returns NULL if the class has not been loaded or // if the verification of constant pool failed Klass* ConstantPool::klass_at_if_loaded(const constantPoolHandle& this_cp, int which) { ! CPKlassSlot kslot = this_cp->klass_slot_at(which); ! int resolved_klass_index = kslot.resolved_klass_index(); ! int name_index = kslot.name_index(); ! assert(this_cp->tag_at(name_index).is_symbol(), "sanity"); ! ! Klass* k = this_cp->resolved_klasses()->at(resolved_klass_index); ! if (k != NULL) { ! return k; } else { Thread *thread = Thread::current(); ! Symbol* name = this_cp->symbol_at(name_index); oop loader = this_cp->pool_holder()->class_loader(); oop protection_domain = this_cp->pool_holder()->protection_domain(); Handle h_prot (thread, protection_domain); Handle h_loader (thread, loader); Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread);
*** 482,507 **** Klass* ConstantPool::klass_ref_at(int which, TRAPS) { return klass_at(klass_ref_index_at(which), THREAD); } - Symbol* ConstantPool::klass_name_at(int which) const { ! assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), ! "Corrupted constant pool"); ! // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*. ! // It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and ! // tag is not updated atomicly. ! CPSlot entry = slot_at(which); ! if (entry.is_resolved()) { ! // Already resolved - return entry's name. ! assert(entry.get_klass()->is_klass(), "must be"); ! return entry.get_klass()->name(); ! } else { ! assert(entry.is_unresolved(), "must be either symbol or klass"); ! return entry.get_symbol(); ! } } Symbol* ConstantPool::klass_ref_at_noresolve(int which) { jint ref_index = klass_ref_index_at(which); return klass_at_noresolve(ref_index); --- 563,574 ---- Klass* ConstantPool::klass_ref_at(int which, TRAPS) { return klass_at(klass_ref_index_at(which), THREAD); } Symbol* ConstantPool::klass_name_at(int which) const { ! return symbol_at(klass_slot_at(which).name_index()); } Symbol* ConstantPool::klass_ref_at_noresolve(int which) { jint ref_index = klass_ref_index_at(which); return klass_at_noresolve(ref_index);
*** 848,858 **** } // Iterate over symbols and decrement ones which are Symbol*s // This is done during GC. ! // Only decrement the UTF8 symbols. Unresolved classes and strings point to // these symbols but didn't increment the reference count. void ConstantPool::unreference_symbols() { for (int index = 1; index < length(); index++) { // Index 0 is unused constantTag tag = tag_at(index); if (tag.is_symbol()) { --- 915,925 ---- } // Iterate over symbols and decrement ones which are Symbol*s // This is done during GC. ! // Only decrement the UTF8 symbols. Strings point to // these symbols but didn't increment the reference count. void ConstantPool::unreference_symbols() { for (int index = 1; index < length(); index++) { // Index 0 is unused constantTag tag = tag_at(index); if (tag.is_symbol()) {
*** 1229,1244 **** const constantPoolHandle& to_cp, int to_i, TRAPS) { int tag = from_cp->tag_at(from_i).value(); switch (tag) { - case JVM_CONSTANT_Class: - { - Klass* k = from_cp->klass_at(from_i, CHECK); - to_cp->klass_at_put(to_i, k); - } break; - case JVM_CONSTANT_ClassIndex: { jint ki = from_cp->klass_index_at(from_i); to_cp->klass_index_at_put(to_i, ki); } break; --- 1296,1305 ----
*** 1303,1324 **** { jint si = from_cp->string_index_at(from_i); to_cp->string_index_at_put(to_i, si); } break; case JVM_CONSTANT_UnresolvedClass: case JVM_CONSTANT_UnresolvedClassInError: { ! // Can be resolved after checking tag, so check the slot first. ! CPSlot entry = from_cp->slot_at(from_i); ! if (entry.is_resolved()) { ! assert(entry.get_klass()->is_klass(), "must be"); ! // Already resolved ! to_cp->klass_at_put(to_i, entry.get_klass()); ! } else { ! to_cp->unresolved_klass_at_put(to_i, entry.get_symbol()); ! } } break; case JVM_CONSTANT_String: { Symbol* s = from_cp->unresolved_string_at(from_i); --- 1364,1381 ---- { jint si = from_cp->string_index_at(from_i); to_cp->string_index_at_put(to_i, si); } break; + case JVM_CONSTANT_Class: case JVM_CONSTANT_UnresolvedClass: case JVM_CONSTANT_UnresolvedClassInError: { ! // Revert to JVM_CONSTANT_ClassIndex ! int name_index = from_cp->klass_slot_at(from_i).name_index(); ! assert(from_cp->tag_at(name_index).is_symbol(), "sanity"); ! to_cp->klass_index_at_put(to_i, name_index); } break; case JVM_CONSTANT_String: { Symbol* s = from_cp->unresolved_string_at(from_i);
*** 1366,1376 **** ShouldNotReachHere(); } break; } } // end copy_entry_to() - // Search constant pool search_cp for an entry that matches this // constant pool's entry at pattern_i. Returns the index of a // matching entry or zero (0) if there is no matching entry. int ConstantPool::find_matching_entry(int pattern_i, const constantPoolHandle& search_cp, TRAPS) { --- 1423,1432 ----
*** 1822,1838 **** --- 1878,1897 ---- void ConstantPool::set_on_stack(const bool value) { if (value) { // Only record if it's not already set. if (!on_stack()) { + assert(!is_shared(), "should always be set for shared constant pools"); _flags |= _on_stack; MetadataOnStackMark::record(this); } } else { // Clearing is done single-threadedly. + if (!is_shared()) { _flags &= ~_on_stack; } + } } // JSR 292 support for patching constant pool oops after the class is linked and // the oop array for resolved references are created. // We can't do this during classfile parsing, which is how the other indexes are
*** 1903,1912 **** --- 1962,1972 ---- st->print_cr(" - holder: " INTPTR_FORMAT, p2i(pool_holder())); } st->print_cr(" - cache: " INTPTR_FORMAT, p2i(cache())); st->print_cr(" - resolved_references: " INTPTR_FORMAT, p2i(resolved_references())); st->print_cr(" - reference_map: " INTPTR_FORMAT, p2i(reference_map())); + st->print_cr(" - resolved_klasses: " INTPTR_FORMAT, p2i(resolved_klasses())); for (int index = 1; index < length(); index++) { // Index 0 is unused ((ConstantPool*)this)->print_entry_on(index, st); switch (tag_at(index).value()) { case JVM_CONSTANT_Long :
*** 1964,1980 **** st->print(" signature_index=%d", signature_ref_index_at(index)); break; case JVM_CONSTANT_Utf8 : symbol_at(index)->print_value_on(st); break; case JVM_CONSTANT_UnresolvedClass : // fall-through case JVM_CONSTANT_UnresolvedClassInError: { ! CPSlot entry = slot_at(index); ! if (entry.is_resolved()) { ! entry.get_klass()->print_value_on(st); } else { ! entry.get_symbol()->print_value_on(st); } } break; case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodHandleInError : --- 2024,2051 ---- st->print(" signature_index=%d", signature_ref_index_at(index)); break; case JVM_CONSTANT_Utf8 : symbol_at(index)->print_value_on(st); break; + case JVM_CONSTANT_ClassIndex: { + int name_index = *int_at_addr(index); + st->print("klass_index=%d ", name_index); + symbol_at(name_index)->print_value_on(st); + } + break; case JVM_CONSTANT_UnresolvedClass : // fall-through case JVM_CONSTANT_UnresolvedClassInError: { ! CPKlassSlot kslot = klass_slot_at(index); ! int resolved_klass_index = kslot.resolved_klass_index(); ! int name_index = kslot.name_index(); ! assert(tag_at(name_index).is_symbol(), "sanity"); ! ! Klass* klass = resolved_klasses()->at(resolved_klass_index); ! if (klass != NULL) { ! klass->print_value_on(st); } else { ! symbol_at(name_index)->print_value_on(st); } } break; case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodHandleInError :
*** 2042,2063 **** void ConstantPool::verify_on(outputStream* st) { guarantee(is_constantPool(), "object must be constant pool"); for (int i = 0; i< length(); i++) { constantTag tag = tag_at(i); ! CPSlot entry = slot_at(i); ! if (tag.is_klass()) { ! if (entry.is_resolved()) { ! guarantee(entry.get_klass()->is_klass(), "should be klass"); ! } ! } else if (tag.is_unresolved_klass()) { ! if (entry.is_resolved()) { ! guarantee(entry.get_klass()->is_klass(), "should be klass"); ! } } else if (tag.is_symbol()) { guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } else if (tag.is_string()) { guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } } if (cache() != NULL) { // Note: cache() can be NULL before a class is completely setup or --- 2113,2129 ---- void ConstantPool::verify_on(outputStream* st) { guarantee(is_constantPool(), "object must be constant pool"); for (int i = 0; i< length(); i++) { constantTag tag = tag_at(i); ! if (tag.is_klass() || tag.is_unresolved_klass()) { ! guarantee(klass_name_at(i)->refcount() != 0, "should have nonzero reference count"); } else if (tag.is_symbol()) { + CPSlot entry = slot_at(i); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } else if (tag.is_string()) { + CPSlot entry = slot_at(i); guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count"); } } if (cache() != NULL) { // Note: cache() can be NULL before a class is completely setup or
< prev index next >