< 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.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()) {
assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
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[].
// Also, see if the element has secondary supertypes.
// We need an array type for each before creating this array type.
! super_klass = element_super->array_klass(CHECK_NULL);
const Array<Klass*>* element_supers = element_klass->secondary_supers();
for (int i = element_supers->length() - 1; i >= 0; i--) {
Klass* elem_super = element_supers->at(i);
elem_super->array_klass(CHECK_NULL);
}
#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, TRAPS) {
+ assert(!null_free || (n == 1 && element_klass->is_inline_klass()), "null-free unsupported");
// Eagerly allocate the direct array supertype.
Klass* super_klass = nullptr;
if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
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[].
// Also, see if the element has secondary supertypes.
// We need an array type for each before creating this array type.
! if (null_free) {
+ super_klass = element_klass->array_klass(CHECK_NULL);
+ } else {
+ super_klass = element_super->array_klass(CHECK_NULL);
+ }
const Array<Klass*>* element_supers = element_klass->secondary_supers();
for (int i = element_supers->length() - 1; i >= 0; i--) {
Klass* elem_super = element_supers->at(i);
elem_super->array_klass(CHECK_NULL);
}
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.
super_klass = vmClasses::Object_klass();
}
}
// Create type name for klass.
! Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, 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);
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);
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);
if (element_klass->is_array_klass()) {
set_lower_dimension(ArrayKlass::cast(element_klass));
}
! 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 {
if (element_klass->is_array_klass()) {
set_lower_dimension(ArrayKlass::cast(element_klass));
}
! 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();
}
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;
ArrayKlass* ld_klass = lower_dimension();
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
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
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[]",
it->push(&_bottom_klass);
}
jint ObjArrayKlass::compute_modifier_flags() const {
// The modifier for an objectArray is the same as its element
if (element_klass() == nullptr) {
assert(Universe::is_bootstrapping(), "partial objArray only at startup");
return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
}
// Return the flags of the bottom element type.
jint element_flags = bottom_klass()->compute_modifier_flags();
return (element_flags & (JVM_ACC_PUBLIC | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED))
! | (JVM_ACC_ABSTRACT | JVM_ACC_FINAL);
}
ModuleEntry* ObjArrayKlass::module() const {
assert(bottom_klass() != nullptr, "ObjArrayKlass returned unexpected null bottom_klass");
// The array is defined in the module of its bottom class
it->push(&_bottom_klass);
}
jint ObjArrayKlass::compute_modifier_flags() const {
// The modifier for an objectArray is the same as its element
+ // With the addition of ACC_IDENTITY
if (element_klass() == nullptr) {
assert(Universe::is_bootstrapping(), "partial objArray only at startup");
return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
}
// Return the flags of the bottom element type.
jint element_flags = bottom_klass()->compute_modifier_flags();
+ int identity_flag = (Arguments::enable_preview()) ? JVM_ACC_IDENTITY : 0;
+
return (element_flags & (JVM_ACC_PUBLIC | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED))
! | (identity_flag | JVM_ACC_ABSTRACT | JVM_ACC_FINAL);
}
ModuleEntry* ObjArrayKlass::module() const {
assert(bottom_klass() != nullptr, "ObjArrayKlass returned unexpected null bottom_klass");
// The array is defined in the module of its bottom class
// 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 >