< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page

        

*** 60,69 **** --- 60,70 ---- #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" + #include "oops/valueKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.hpp" #include "prims/methodComparator.hpp" #include "runtime/atomic.hpp"
*** 368,378 **** 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(parser.is_unsafe_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"); --- 369,381 ---- 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(parser.is_unsafe_anonymous()), ! parser.has_flattenable_fields() ? parser.java_fields_count() : 0, ! parser.is_value_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");
*** 382,395 **** // 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::_misc_kind_other); } } else { --- 385,400 ---- // 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_value_type()) { + // value type + ik = new (loader_data, size, THREAD) ValueKlass(parser); } else { // normal ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other); } } else {
*** 401,413 **** --- 406,448 ---- // 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?)
*** 434,451 **** _nest_host_index(0), _nest_host(NULL), _static_field_size(parser.static_field_size()), _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())), _itable_len(parser.itable_size()), ! _reference_type(parser.reference_type()) ! { set_vtable_length(parser.vtable_size()); set_kind(kind); set_access_flags(parser.access_flags()); 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?"); --- 469,491 ---- _nest_host_index(0), _nest_host(NULL), _static_field_size(parser.static_field_size()), _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())), _itable_len(parser.itable_size()), ! _extra_flags(0), ! _reference_type(parser.reference_type()), ! _adr_valueklass_fixed_block(NULL) { set_vtable_length(parser.vtable_size()); set_kind(kind); set_access_flags(parser.access_flags()); set_is_unsafe_anonymous(parser.is_unsafe_anonymous()); set_layout_helper(Klass::instance_layout_helper(parser.layout_size(), false)); + if (parser.has_flattenable_fields()) { + set_has_value_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?");
*** 787,796 **** --- 827,897 ---- 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 a value class as an argument + // type or return value type, this value class must be loaded during the + // linking of this class because size and properties of the value class + // must be known in order to be able to perform value 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. + // This is also the moment to detect potential mismatch between the + // ValueTypes attribute and the kind of the class effectively loaded. + + + // Note: + // Value class types used for flattenable fields are loaded during + // the loading phase (see ClassFileParser::post_process_parsed_stream()). + // Value 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 value 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()) { + Symbol* sig = ss.as_symbol(THREAD); + if (ss.is_object()) { + Symbol* symb = sig; + if (ss.is_array()) { + int i=0; + while (sig->char_at(i) == '[') i++; + if (i == sig->utf8_length() - 1 ) continue; // primitive array + symb = SymbolTable::lookup(sig->as_C_string() + i + 1, + sig->utf8_length() - 3, CHECK_false); + } + if (ss.type() == T_VALUETYPE) { + 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 (symb != sig) { + symb->decrement_refcount(); + } + if (klass == NULL) { + THROW_(vmSymbols::java_lang_LinkageError(), false); + } + if (!klass->is_value()) { + THROW_(vmSymbols::java_lang_IncompatibleClassChangeError(), false); + } + } + } + } + } + } + // in case the class is linked in the process of linking its superclasses if (is_linked()) { return true; }
*** 856,865 **** --- 957,967 ---- 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);
*** 1009,1023 **** 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); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(), --- 1111,1136 ---- DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait); THROW_OOP(e()); } } + // Step 8 + // Initialize classes of flattenable fields + { + for (AllFieldStream fs(this); !fs.done(); fs.next()) { + if (fs.is_flattenable()) { + InstanceKlass* field_klass = InstanceKlass::cast(this->get_value_field_klass(fs.index())); + field_klass->initialize(CHECK); + } + } + } + // 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); // Timer includes any side effects of class initialization (resolution, // etc), but not recursive entry into call_class_initializer(). PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
*** 1027,1045 **** jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_CLINIT); 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); --- 1140,1158 ---- jt->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_CLINIT); 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);
*** 1357,1367 **** InterpreterOopMap* entry_for) { // Lazily create the _oop_map_cache at first request // Lock-free access requires load_acquire. OopMapCache* oop_map_cache = OrderAccess::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 OrderAccess::release_store(&_oop_map_cache, oop_map_cache); --- 1470,1480 ---- InterpreterOopMap* entry_for) { // Lazily create the _oop_map_cache at first request // Lock-free access requires load_acquire. OopMapCache* oop_map_cache = OrderAccess::load_acquire(&_oop_map_cache); if (oop_map_cache == NULL) { ! MutexLockerEx 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 OrderAccess::release_store(&_oop_map_cache, oop_map_cache);
*** 2519,2528 **** --- 2632,2649 ---- // Decrement symbol reference counts associated with the unloaded class. if (_name != NULL) _name->decrement_refcount(); // unreference array name derived from this class name (arrays of an unloaded // class can't be referenced anymore). if (_array_name != NULL) _array_name->decrement_refcount(); + if (_value_types != NULL) { + for (int i = 0; i < _value_types->length(); i++) { + Symbol* s = _value_types->at(i)._class_name; + if (s != NULL) { + s->decrement_refcount(); + } + } + } if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(char, _source_debug_extension); } void InstanceKlass::set_source_debug_extension(const char* array, int length) { if (array == NULL) {
*** 2541,2550 **** --- 2662,2675 ---- _source_debug_extension = sde; } } const char* InstanceKlass::signature_name() const { + return signature_name_of(is_value() ? 'Q' : 'L'); + } + + const char* InstanceKlass::signature_name_of(char c) const { int hash_len = 0; char hash_buf[40]; // If this is an unsafe anonymous class, append a hash to make the name unique if (is_unsafe_anonymous()) {
*** 2557,2569 **** 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++] = 'L'; // Add the actual class name for (int src_index = 0; src_index < src_length; ) { dest[dest_index++] = src[src_index++]; } --- 2682,2694 ---- 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++] = c; // Add the actual class name for (int src_index = 0; src_index < src_length; ) { dest[dest_index++] = src[src_index++]; }
*** 3081,3113 **** 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 (e != 0 && ((Metadata*)e)->is_metaspace_object()) { 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(); --- 3206,3274 ---- 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 (e != 0 && ((Metadata*)e)->is_metaspace_object()) { 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();
*** 3130,3159 **** 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(); --- 3291,3308 ---- 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();
*** 3202,3212 **** 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); --- 3351,3361 ---- 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);
*** 3976,3980 **** --- 4125,4134 ---- 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 >