< 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 >