< prev index next > src/hotspot/share/oops/objArrayKlass.cpp
Print this page
#include "classfile/vmSymbols.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
+ #include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/arrayKlass.inline.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/macros.hpp"
! ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, Klass* k, Symbol* name, TRAPS) {
assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(),
"array klasses must be same size as InstanceKlass");
int size = ArrayKlass::static_size(ObjArrayKlass::header_size());
! return new (loader_data, size, THREAD) ObjArrayKlass(n, k, name);
}
ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
! int n, Klass* element_klass, TRAPS) {
// Eagerly allocate the direct array supertype.
Klass* super_klass = nullptr;
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
Klass* element_super = element_klass->super();
if (element_super != nullptr) {
// The element type has a direct super. E.g., String[] has direct super of Object[].
! super_klass = element_super->array_klass_or_null();
bool supers_exist = super_klass != nullptr;
// Also, see if the element has secondary supertypes.
// We need an array type for each.
const Array<Klass*>* element_supers = element_klass->secondary_supers();
for( int i = element_supers->length()-1; i >= 0; i-- ) {
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/macros.hpp"
! ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n,
+ Klass* k, Symbol* name, bool null_free,
+ TRAPS) {
assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(),
"array klasses must be same size as InstanceKlass");
int size = ArrayKlass::static_size(ObjArrayKlass::header_size());
! return new (loader_data, size, THREAD) ObjArrayKlass(n, k, name, null_free);
}
ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
! int n, Klass* element_klass,
+ bool null_free, bool qdesc, TRAPS) {
+ assert(!null_free || (n == 1 && element_klass->is_inline_klass() && qdesc), "null-free unsupported");
// Eagerly allocate the direct array supertype.
Klass* super_klass = nullptr;
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
Klass* element_super = element_klass->super();
if (element_super != nullptr) {
// The element type has a direct super. E.g., String[] has direct super of Object[].
! if (null_free) {
+ super_klass = element_klass->array_klass_or_null();
+ } else {
+ super_klass = element_super->array_klass_or_null();
+ }
bool supers_exist = super_klass != nullptr;
// Also, see if the element has secondary supertypes.
// We need an array type for each.
const Array<Klass*>* element_supers = element_klass->secondary_supers();
for( int i = element_supers->length()-1; i >= 0; i-- ) {
if (elem_super->array_klass_or_null() == nullptr) {
supers_exist = false;
break;
}
}
if (!supers_exist) {
// Oops. Not allocated yet. Back out, allocate it, and retry.
Klass* ek = nullptr;
{
MutexUnlocker mu(MultiArray_lock);
! super_klass = element_super->array_klass(CHECK_NULL);
for( int i = element_supers->length()-1; i >= 0; i-- ) {
Klass* elem_super = element_supers->at(i);
elem_super->array_klass(CHECK_NULL);
}
// Now retry from the beginning
! ek = element_klass->array_klass(n, CHECK_NULL);
} // re-lock
return ObjArrayKlass::cast(ek);
}
} else {
// The element type is already Object. Object[] has direct super of Object.
super_klass = vmClasses::Object_klass();
}
}
// Create type name for klass.
! Symbol* name = nullptr;
- {
- ResourceMark rm(THREAD);
- char *name_str = element_klass->name()->as_C_string();
- int len = element_klass->name()->utf8_length();
- char *new_str = NEW_RESOURCE_ARRAY(char, len + 4);
- int idx = 0;
- new_str[idx++] = JVM_SIGNATURE_ARRAY;
- if (element_klass->is_instance_klass()) { // it could be an array or simple type
- new_str[idx++] = JVM_SIGNATURE_CLASS;
- }
- memcpy(&new_str[idx], name_str, len * sizeof(char));
- idx += len;
- if (element_klass->is_instance_klass()) {
- new_str[idx++] = JVM_SIGNATURE_ENDCLASS;
- }
- new_str[idx++] = '\0';
- name = SymbolTable::new_symbol(new_str);
- }
// Initialize instance variables
! ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, CHECK_NULL);
ModuleEntry* module = oak->module();
assert(module != nullptr, "No module entry for array");
// Call complete_create_array_klass after all instance variables has been initialized.
if (elem_super->array_klass_or_null() == nullptr) {
supers_exist = false;
break;
}
}
+ if (null_free) {
+ if (element_klass->array_klass_or_null() == nullptr) {
+ supers_exist = false;
+ }
+ }
if (!supers_exist) {
// Oops. Not allocated yet. Back out, allocate it, and retry.
Klass* ek = nullptr;
{
MutexUnlocker mu(MultiArray_lock);
! if (null_free) {
+ element_klass->array_klass(CHECK_NULL);
+ } else {
+ element_super->array_klass(CHECK_NULL);
+ }
for( int i = element_supers->length()-1; i >= 0; i-- ) {
Klass* elem_super = element_supers->at(i);
elem_super->array_klass(CHECK_NULL);
}
// Now retry from the beginning
! if (null_free) {
+ ek = InlineKlass::cast(element_klass)->value_array_klass(CHECK_NULL);
+ } else {
+ ek = element_klass->array_klass(n, CHECK_NULL);
+ }
} // re-lock
return ObjArrayKlass::cast(ek);
}
} else {
// The element type is already Object. Object[] has direct super of Object.
super_klass = vmClasses::Object_klass();
}
}
// Create type name for klass.
! Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, qdesc, CHECK_NULL);
// Initialize instance variables
! ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, null_free, CHECK_NULL);
ModuleEntry* module = oak->module();
assert(module != nullptr, "No module entry for array");
// Call complete_create_array_klass after all instance variables has been initialized.
loader_data->add_class(oak);
return oak;
}
! ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, Kind) {
set_dimension(n);
set_element_klass(element_klass);
Klass* bk;
if (element_klass->is_objArray_klass()) {
bk = ObjArrayKlass::cast(element_klass)->bottom_klass();
} else {
bk = element_klass;
}
assert(bk != nullptr && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
set_bottom_klass(bk);
set_class_loader_data(bk->class_loader_data());
! set_layout_helper(array_layout_helper(T_OBJECT));
assert(is_array_klass(), "sanity");
assert(is_objArray_klass(), "sanity");
}
size_t ObjArrayKlass::oop_size(oop obj) const {
loader_data->add_class(oak);
return oak;
}
! ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool null_free) : ArrayKlass(name, Kind) {
set_dimension(n);
set_element_klass(element_klass);
+ assert(!null_free || name->is_Q_array_signature(), "sanity check");
+
Klass* bk;
if (element_klass->is_objArray_klass()) {
bk = ObjArrayKlass::cast(element_klass)->bottom_klass();
+ } else if (element_klass->is_flatArray_klass()) {
+ bk = FlatArrayKlass::cast(element_klass)->element_klass();
} else {
bk = element_klass;
}
assert(bk != nullptr && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
set_bottom_klass(bk);
set_class_loader_data(bk->class_loader_data());
! int lh = array_layout_helper(T_OBJECT);
+ if (null_free) {
+ assert(n == 1, "Bytecode does not support null-free multi-dim");
+ lh = layout_helper_set_null_free(lh);
+ #ifdef _LP64
+ set_prototype_header(markWord::null_free_array_prototype());
+ assert(prototype_header().is_null_free_array(), "sanity");
+ #else
+ set_prototype_header(markWord::inline_type_prototype());
+ #endif
+ }
+ set_layout_helper(lh);
assert(is_array_klass(), "sanity");
assert(is_objArray_klass(), "sanity");
}
size_t ObjArrayKlass::oop_size(oop obj) const {
}
objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
size_t size = objArrayOopDesc::object_size(length);
! return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
! /* do_zero */ true, THREAD);
}
oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
int length = *sizes;
ArrayKlass* ld_klass = lower_dimension();
// If length < 0 allocate will throw an exception.
objArrayOop array = allocate(length, CHECK_NULL);
objArrayHandle h_array (THREAD, array);
! if (rank > 1) {
! if (length != 0) {
! for (int index = 0; index < length; index++) {
! oop sub_array = ld_klass->multi_allocate(rank - 1, &sizes[1], CHECK_NULL);
! h_array->obj_at_put(index, sub_array);
! }
! } else {
! // Since this array dimension has zero length, nothing will be
! // allocated, however the lower dimension values must be checked
! // for illegal values.
! for (int i = 0; i < rank - 1; ++i) {
! sizes += 1;
! if (*sizes < 0) {
- THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes));
- }
}
}
}
return h_array();
}
}
objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
size_t size = objArrayOopDesc::object_size(length);
! bool populate_null_free = is_null_free_array_klass();
! objArrayOop array = (objArrayOop)Universe::heap()->array_allocate(this, size, length,
+ /* do_zero */ true, CHECK_NULL);
+ objArrayHandle array_h(THREAD, array);
+ if (populate_null_free) {
+ assert(dimension() == 1, "Can only populate the final dimension");
+ assert(element_klass()->is_inline_klass(), "Unexpected");
+ assert(!element_klass()->is_array_klass(), "ArrayKlass unexpected here");
+ assert(!InlineKlass::cast(element_klass())->flat_array(), "Expected flatArrayOop allocation");
+ element_klass()->initialize(CHECK_NULL);
+ // Populate default values...
+ instanceOop value = (instanceOop) InlineKlass::cast(element_klass())->default_value();
+ for (int i = 0; i < length; i++) {
+ array_h->obj_at_put(i, value);
+ }
+ }
+ return array_h();
}
oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
int length = *sizes;
+ if (rank == 1) { // last dim may be flatArray, check if we have any special storage requirements
+ if (name()->char_at(1) != JVM_SIGNATURE_ARRAY && name()->is_Q_array_signature()) {
+ return oopFactory::new_valueArray(element_klass(), length, CHECK_NULL);
+ } else {
+ return oopFactory::new_objArray(element_klass(), length, CHECK_NULL);
+ }
+ }
+ guarantee(rank > 1, "Rank below 1");
+ // Call to lower_dimension uses this pointer, so most be called before a
+ // possible GC
ArrayKlass* ld_klass = lower_dimension();
// If length < 0 allocate will throw an exception.
objArrayOop array = allocate(length, CHECK_NULL);
objArrayHandle h_array (THREAD, array);
! if (length != 0) {
! for (int index = 0; index < length; index++) {
! oop sub_array = ld_klass->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
! h_array->obj_at_put(index, sub_array);
! }
! } else {
! // Since this array dimension has zero length, nothing will be
! // allocated, however the lower dimension values must be checked
! // for illegal values.
! for (int i = 0; i < rank - 1; ++i) {
! sizes += 1;
! if (*sizes < 0) {
! THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes));
}
}
}
return h_array();
}
ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
} else {
// We have to make sure all elements conform to the destination array
Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
if (stype == bound || stype->is_subtype_of(bound)) {
! // elements are guaranteed to be subtypes, so no check necessary
! ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
} else {
! // slow case: need individual subtype checks
! // note: don't use obj_at_put below because it includes a redundant store check
! if (!ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length)) {
! ResourceMark rm(THREAD);
- stringStream ss;
- if (!bound->is_subtype_of(stype)) {
- ss.print("arraycopy: type mismatch: can not copy %s[] into %s[]",
- stype->external_name(), bound->external_name());
- } else {
- // oop_arraycopy should return the index in the source array that
- // contains the problematic oop.
- ss.print("arraycopy: element type mismatch: can not cast one of the elements"
- " of %s[] to the type of the destination array, %s",
- stype->external_name(), bound->external_name());
- }
- THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
}
}
}
}
void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
int dst_pos, int length, TRAPS) {
assert(s->is_objArray(), "must be obj array");
if (!d->is_objArray()) {
ResourceMark rm(THREAD);
stringStream ss;
if (d->is_typeArray()) {
ss.print("arraycopy: type mismatch: can not copy object array[] into %s[]",
ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
} else {
// We have to make sure all elements conform to the destination array
Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
+ // Perform null check if dst is null-free but src has no such guarantee
+ bool null_check = ((!s->klass()->is_null_free_array_klass()) &&
+ d->klass()->is_null_free_array_klass());
if (stype == bound || stype->is_subtype_of(bound)) {
! if (null_check) {
! ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length);
+ } else {
+ ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
+ }
} else {
! if (null_check) {
! ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length);
! } else {
! ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length);
}
}
}
}
void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
int dst_pos, int length, TRAPS) {
assert(s->is_objArray(), "must be obj array");
+ if (UseFlatArray) {
+ if (d->is_flatArray()) {
+ FlatArrayKlass::cast(d->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD);
+ return;
+ }
+ }
+
if (!d->is_objArray()) {
ResourceMark rm(THREAD);
stringStream ss;
if (d->is_typeArray()) {
ss.print("arraycopy: type mismatch: can not copy object array[] into %s[]",
// Check if another thread beat us
if (higher_dimension() == nullptr) {
// Create multi-dim klass object and link them together
! ObjArrayKlass* ak =
! ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, CHECK_NULL);
ak->set_lower_dimension(this);
// use 'release' to pair with lock-free load
release_set_higher_dimension(ak);
assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");
}
// Check if another thread beat us
if (higher_dimension() == nullptr) {
// Create multi-dim klass object and link them together
! ObjArrayKlass* ak = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this,
! false, this->name()->is_Q_array_signature(), CHECK_NULL);
ak->set_lower_dimension(this);
// use 'release' to pair with lock-free load
release_set_higher_dimension(ak);
assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");
}
// Printing
void ObjArrayKlass::print_on(outputStream* st) const {
#ifndef PRODUCT
Klass::print_on(st);
! st->print(" - instance klass: ");
element_klass()->print_value_on(st);
st->cr();
#endif //PRODUCT
}
// Printing
void ObjArrayKlass::print_on(outputStream* st) const {
#ifndef PRODUCT
Klass::print_on(st);
! st->print(" - element klass: ");
element_klass()->print_value_on(st);
st->cr();
#endif //PRODUCT
}
void ObjArrayKlass::verify_on(outputStream* st) {
ArrayKlass::verify_on(st);
guarantee(element_klass()->is_klass(), "should be klass");
guarantee(bottom_klass()->is_klass(), "should be klass");
Klass* bk = bottom_klass();
! guarantee(bk->is_instance_klass() || bk->is_typeArray_klass(), "invalid bottom klass");
}
void ObjArrayKlass::oop_verify_on(oop obj, outputStream* st) {
ArrayKlass::oop_verify_on(obj, st);
guarantee(obj->is_objArray(), "must be objArray");
objArrayOop oa = objArrayOop(obj);
for(int index = 0; index < oa->length(); index++) {
guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop");
}
}
void ObjArrayKlass::verify_on(outputStream* st) {
ArrayKlass::verify_on(st);
guarantee(element_klass()->is_klass(), "should be klass");
guarantee(bottom_klass()->is_klass(), "should be klass");
Klass* bk = bottom_klass();
! guarantee(bk->is_instance_klass() || bk->is_typeArray_klass() || bk->is_flatArray_klass(),
+ "invalid bottom klass");
}
void ObjArrayKlass::oop_verify_on(oop obj, outputStream* st) {
ArrayKlass::oop_verify_on(obj, st);
guarantee(obj->is_objArray(), "must be objArray");
+ guarantee(obj->is_null_free_array() || (!is_null_free_array_klass()), "null-free klass but not object");
objArrayOop oa = objArrayOop(obj);
for(int index = 0; index < oa->length(); index++) {
guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop");
}
}
< prev index next >