diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index c7225e441db..dfa8f7908bb 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -747,16 +747,16 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { __ stop("assert(is a type array klass)"); break; case C1StubId::new_object_array_id: - __ cmpw(t0, Klass::_lh_array_tag_obj_value); // new "[Ljava/lang/Object;" + __ cmpw(t0, Klass::_lh_array_tag_ref_value); // new "[Ljava/lang/Object;" __ br(Assembler::EQ, ok); - __ cmpw(t0, Klass::_lh_array_tag_vt_value); // new "[LVT;" + __ cmpw(t0, Klass::_lh_array_tag_flat_value); // new "[LVT;" __ br(Assembler::EQ, ok); __ stop("assert(is an object or inline type array klass)"); break; case C1StubId::new_null_free_array_id: - __ cmpw(t0, Klass::_lh_array_tag_vt_value); // the array can be a flat array. + __ cmpw(t0, Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ br(Assembler::EQ, ok); - __ cmpw(t0, Klass::_lh_array_tag_obj_value); // the array cannot be a flat array (due to InlineArrayElementMaxFlatSize, etc) + __ cmpw(t0, Klass::_lh_array_tag_ref_value); // the array cannot be a flat array (due to the InlineArrayElementMaxFlatSize, etc.) __ br(Assembler::EQ, ok); __ stop("assert(is an object or inline type array klass)"); break; diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 79b129c08ae..11770a29889 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -444,7 +444,7 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { #ifdef ASSERT // Assert object type is really an array of the proper kind. { - int tag = (id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value; + int tag = (id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_ref_value; Label ok; __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R4_ARG2); __ srawi(R0, R0, Klass::_lh_array_tag_shift); diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp index 849417725a7..fa27369baf6 100644 --- a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -753,7 +753,7 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { Register tmp = obj; __ lwu(tmp, Address(klass, Klass::layout_helper_offset())); __ sraiw(tmp, tmp, Klass::_lh_array_tag_shift); - int tag = ((id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value); + int tag = ((id == C1StubId::new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_ref_value); __ mv(t0, tag); __ beq(t0, tmp, ok); __ stop("assert(is an array klass)"); diff --git a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp index db04703ceb0..47ed57d4008 100644 --- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp +++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp @@ -396,8 +396,7 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { __ mem2reg_opt(t0, Address(klass, Klass::layout_helper_offset()), false); __ z_sra(t0, Klass::_lh_array_tag_shift); int tag = ((id == C1StubId::new_type_array_id) - ? Klass::_lh_array_tag_type_value - : Klass::_lh_array_tag_obj_value); + ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_ref_value); __ compare32_and_branch(t0, tag, Assembler::bcondEqual, ok); __ stop("assert(is an array klass)"); __ should_not_reach_here(); diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index 2b4d2b76923..718939f518d 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -911,16 +911,16 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) { __ stop("assert(is a type array klass)"); break; case C1StubId::new_object_array_id: - __ cmpl(t0, Klass::_lh_array_tag_obj_value); // new "[Ljava/lang/Object;" + __ cmpl(t0, (Klass::_lh_array_tag_ref_value)); // new "[Ljava/lang/Object;" __ jcc(Assembler::equal, ok); - __ cmpl(t0, Klass::_lh_array_tag_vt_value); // new "[LVT;" + __ cmpl(t0, Klass::_lh_array_tag_flat_value); // new "[LVT;" __ jcc(Assembler::equal, ok); __ stop("assert(is an object or inline type array klass)"); break; case C1StubId::new_null_free_array_id: - __ cmpl(t0, Klass::_lh_array_tag_vt_value); // the array can be a flat array. + __ cmpl(t0, Klass::_lh_array_tag_flat_value); // the array can be a flat array. __ jcc(Assembler::equal, ok); - __ cmpl(t0, Klass::_lh_array_tag_obj_value); // the array cannot be a flat array (due to InlineArrayElementMaxFlatSize, etc) + __ cmpl(t0, (Klass::_lh_array_tag_ref_value)); // the array cannot be a flat array (due to InlineArrayElementMaxFlatSize, etc) __ jcc(Assembler::equal, ok); __ stop("assert(is an object or inline type array klass)"); break; diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 7efa3c760ba..866d9350040 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -419,7 +419,7 @@ JRT_ENTRY(void, Runtime1::new_object_array(JavaThread* current, Klass* array_kla // (This may have to change if this code changes!) assert(array_klass->is_klass(), "not a class"); Handle holder(current, array_klass->klass_holder()); // keep the klass alive - Klass* elem_klass = ArrayKlass::cast(array_klass)->element_klass(); + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK); current->set_vm_result_oop(obj); // This is pretty rare but this runtime patch is stressful to deoptimization @@ -439,14 +439,14 @@ JRT_ENTRY(void, Runtime1::new_null_free_array(JavaThread* current, Klass* array_ // (This may have to change if this code changes!) assert(array_klass->is_klass(), "not a class"); Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive - Klass* elem_klass = ArrayKlass::cast(array_klass)->element_klass(); + Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); assert(elem_klass->is_inline_klass(), "must be"); InlineKlass* vk = InlineKlass::cast(elem_klass); // Logically creates elements, ensure klass init elem_klass->initialize(CHECK); arrayOop obj= nullptr; if (UseArrayFlattening && vk->has_non_atomic_layout()) { - obj = oopFactory::new_flatArray(elem_klass, length, LayoutKind::NON_ATOMIC_FLAT, CHECK); + obj = oopFactory::new_flatArray(elem_klass, length, ArrayKlass::ArrayProperties::NULL_RESTRICTED, LayoutKind::NON_ATOMIC_FLAT, CHECK); } else { obj = oopFactory::new_null_free_objArray(elem_klass, length, CHECK); } @@ -516,7 +516,7 @@ JRT_ENTRY(void, Runtime1::load_flat_array(JavaThread* current, flatArrayOopDesc* NOT_PRODUCT(_load_flat_array_slowcase_cnt++;) assert(array->length() > 0 && index < array->length(), "already checked"); flatArrayHandle vah(current, array); - oop obj = array->read_value_from_flat_array(index, CHECK); + oop obj = array->obj_at(index, CHECK); current->set_vm_result_oop(obj); JRT_END @@ -531,7 +531,7 @@ JRT_ENTRY(void, Runtime1::store_flat_array(JavaThread* current, flatArrayOopDesc SharedRuntime::throw_and_post_jvmti_exception(current, vmSymbols::java_lang_NullPointerException()); } else { assert(array->klass()->is_flatArray_klass(), "should not be called"); - array->write_value_to_flat_array(value, index, CHECK); + array->obj_at_put(index, value, CHECK); } JRT_END diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 54bca6679ff..7c8912747ab 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -184,7 +184,7 @@ void ArchiveHeapWriter::ensure_buffer_space(size_t min_bytes) { objArrayOop ArchiveHeapWriter::allocate_root_segment(size_t offset, int element_count) { HeapWord* mem = offset_to_buffered_address(offset); - memset(mem, 0, objArrayOopDesc::object_size(element_count)); + memset(mem, 0, refArrayOopDesc::object_size(element_count)); // The initialization code is copied from MemAllocator::finish and ObjArrayAllocator::initialize. if (UseCompactObjectHeaders) { @@ -220,7 +220,7 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapreplace_if_null(index, o); + // ((objArrayOop)array.resolve())->replace_if_null(index, o); + refArrayOopDesc::cast(array.resolve())->replace_if_null(index, o); } oop CDSProtectionDomain::shared_protection_domain(int index) { diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index 0d602b31a2a..3d0313812a6 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -37,6 +37,7 @@ #include "oops/instanceStackChunkKlass.hpp" #include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/refArrayKlass.hpp" #include "oops/typeArrayKlass.hpp" #include "runtime/arguments.hpp" #include "utilities/globalDefinitions.hpp" @@ -67,7 +68,8 @@ f(ObjArrayKlass) \ f(TypeArrayKlass) \ f(FlatArrayKlass) \ - f(InlineKlass) + f(InlineKlass) \ + f(RefArrayKlass) class CppVtableInfo { intptr_t _vtable_size; diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index 5d539f4cac4..c368f35e697 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -457,7 +457,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { soc->do_tag(arrayOopDesc::base_offset_in_bytes(T_BYTE)); soc->do_tag(sizeof(ConstantPool)); soc->do_tag(sizeof(ConstantPoolCache)); - soc->do_tag(objArrayOopDesc::base_offset_in_bytes()); + soc->do_tag(refArrayOopDesc::base_offset_in_bytes()); soc->do_tag(typeArrayOopDesc::base_offset_in_bytes(T_BYTE)); soc->do_tag(sizeof(Symbol)); diff --git a/src/hotspot/share/ci/ciArrayKlass.cpp b/src/hotspot/share/ci/ciArrayKlass.cpp index 03011bb2a54..6726cd5b637 100644 --- a/src/hotspot/share/ci/ciArrayKlass.cpp +++ b/src/hotspot/share/ci/ciArrayKlass.cpp @@ -131,7 +131,7 @@ ciArrayKlass* ciArrayKlass::make(ciType* element_type, bool flat, bool null_free lk = LayoutKind::NULLABLE_ATOMIC_FLAT; } } - ak = vk->flat_array_klass(lk, THREAD); + ak = vk->flat_array_klass(ArrayKlass::ArrayProperties::DUMMY, lk, THREAD); } else if (null_free) { ak = vk->null_free_reference_array(THREAD); } else { diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index e34048cc655..77560bcd115 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -396,7 +396,7 @@ ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { return new (arena()) ciInstanceKlass(k); } else if (k->is_flatArray_klass()) { return new (arena()) ciFlatArrayKlass(k); - } else if (k->is_objArray_klass()) { + } else if (k->is_refArray_klass()) { return new (arena()) ciObjArrayKlass(k); } else if (k->is_typeArray_klass()) { return new (arena()) ciTypeArrayKlass(k); diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ac547430315..5dec04fe095 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1091,7 +1091,7 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti comp_mirror = Handle(THREAD, Universe::java_mirror(type)); } } else { - assert(k->is_objArray_klass(), "Must be"); + assert(k->is_refArray_klass(), "Must be"); Klass* element_klass = ObjArrayKlass::cast(k)->element_klass(); assert(element_klass != nullptr, "Must have an element klass"); oop comp_oop = element_klass->java_mirror(); diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 1076ffb2dd7..232b7ba8607 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -951,7 +951,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { } int total = (int)_items_count; - size_t single_array_size = objArrayOopDesc::object_size(total); + size_t single_array_size = refArrayOopDesc::object_size(total); log_info(cds)("allocated string table for %d strings", total); @@ -963,8 +963,8 @@ void StringTable::allocate_shared_strings_array(TRAPS) { } else { // Split the table in two levels of arrays. int primary_array_length = (total + _secondary_array_max_length - 1) / _secondary_array_max_length; - size_t primary_array_size = objArrayOopDesc::object_size(primary_array_length); - size_t secondary_array_size = objArrayOopDesc::object_size(_secondary_array_max_length); + size_t primary_array_size = refArrayOopDesc::object_size(primary_array_length); + size_t secondary_array_size = refArrayOopDesc::object_size(_secondary_array_max_length); if (ArchiveHeapWriter::is_too_large_to_archive(secondary_array_size)) { // This can only happen if you have an extremely large number of classes that @@ -1004,7 +1004,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { void StringTable::verify_secondary_array_index_bits() { int max; for (max = 1; ; max++) { - size_t next_size = objArrayOopDesc::object_size(1 << (max + 1)); + size_t next_size = refArrayOopDesc::object_size(1 << (max + 1)); if (ArchiveHeapWriter::is_too_large_to_archive(next_size)) { break; } diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 6cbfe2674e8..a7fa0a4bdce 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -107,13 +107,13 @@ void G1FullGCMarker::follow_array_chunk(objArrayOop array, int index) { if (end_index < len) { push_objarray(array, end_index); } - - array->oop_iterate_range(mark_closure(), beg_index, end_index); + assert(array->is_refArray(), "Must be"); + refArrayOop(array)->oop_iterate_range(mark_closure(), beg_index, end_index); } inline void G1FullGCMarker::follow_object(oop obj) { assert(_bitmap->is_marked(obj), "should be marked"); - if (obj->is_objArray()) { + if (obj->is_refArray()) { // Handle object arrays explicitly to allow them to // be split into chunks if needed. follow_array((objArrayOop)obj); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 0e769a383b4..7f9c65a6752 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -232,7 +232,8 @@ void G1ParScanThreadState::do_partial_array(PartialArrayState* state, bool stole G1HeapRegionAttr dest_attr = _g1h->region_attr(to_array); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_new_survivor()); // Process claimed task. - to_array->oop_iterate_range(&_scanner, + assert(to_array->is_refArray(), "Must be"); + refArrayOop(to_array)->oop_iterate_range(&_scanner, checked_cast(claim._start), checked_cast(claim._end)); } @@ -254,7 +255,8 @@ void G1ParScanThreadState::start_partial_objarray(oop from_obj, // Process the initial chunk. No need to process the type in the // klass, as it will already be handled by processing the built-in // module. - to_array->oop_iterate_range(&_scanner, 0, checked_cast(initial_chunk_size)); + assert(to_array->is_refArray(), "Must be"); + refArrayOop(to_array)->oop_iterate_range(&_scanner, 0, checked_cast(initial_chunk_size)); } MAYBE_INLINE_EVACUATION @@ -428,7 +430,7 @@ void G1ParScanThreadState::do_iterate_object(oop const obj, if (klass->is_array_klass() && !klass->is_flatArray_klass()) { assert(!klass->is_stack_chunk_instance_klass(), "must be"); - if (klass->is_objArray_klass()) { + if (klass->is_refArray_klass()) { start_partial_objarray(old, obj); } else { // Nothing needs to be done for typeArrays. Body doesn't contain diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 2c0b8480726..13a29986b66 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -133,7 +133,7 @@ inline void ParCompactionManager::follow_contents(const ScannerTask& task, bool } else { oop obj = task.to_oop(); assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); - if (obj->is_objArray()) { + if (obj->is_refArray()) { push_objArray(obj); } else { obj->oop_iterate(&_mark_and_push_closure); diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 15468704547..75dc3710867 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -380,6 +380,7 @@ template void SerialFullGC::KeepAliveClosure::do_oop_work(T* p) { } void SerialFullGC::push_objarray(oop obj, size_t index) { + assert(obj->is_refArray(), "Must be"); ObjArrayTask task(obj, index); assert(task.is_valid(), "bad ObjArrayTask"); _objarray_stack.push(task); @@ -395,7 +396,7 @@ void SerialFullGC::follow_array(objArrayOop array) { void SerialFullGC::follow_object(oop obj) { assert(obj->is_gc_marked(), "should be marked"); - if (obj->is_objArray()) { + if (obj->is_refArray()) { // Handle object arrays explicitly to allow them to // be split into chunks if needed. SerialFullGC::follow_array((objArrayOop)obj); @@ -412,7 +413,7 @@ void SerialFullGC::follow_array_chunk(objArrayOop array, int index) { const int stride = MIN2(len - beg_index, (int) ObjArrayMarkingStride); const int end_index = beg_index + stride; - array->oop_iterate_range(&mark_and_push_closure, beg_index, end_index); + refArrayOop(array)->oop_iterate_range(&mark_and_push_closure, beg_index, end_index); if (end_index < len) { SerialFullGC::push_objarray(array, end_index); // Push the continuation. diff --git a/src/hotspot/share/gc/shared/memAllocator.hpp b/src/hotspot/share/gc/shared/memAllocator.hpp index b1f3f8ad35f..2076d59f5c2 100644 --- a/src/hotspot/share/gc/shared/memAllocator.hpp +++ b/src/hotspot/share/gc/shared/memAllocator.hpp @@ -32,7 +32,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" -// These fascilities are used for allocating, and initializing newly allocated objects. +// These facilities are used for allocating, and initializing newly allocated objects. class MemAllocator: StackObj { protected: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 2dc0813e513..185aabc0495 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -85,7 +85,7 @@ void ShenandoahMark::do_task(ShenandoahObjToScanQueue* q, T* cl, ShenandoahLiveD obj->oop_iterate(cl); dedup_string(obj, req); - } else if (obj->is_objArray()) { + } else if (obj->is_refArray()) { // Case 2: Object array instance and no chunk is set. Must be the first // time we visit it, start the chunked processing. do_chunked_array_start(q, cl, obj, weak); @@ -156,7 +156,7 @@ inline void ShenandoahMark::count_liveness(ShenandoahLiveData* live_data, oop ob template inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj, bool weak) { - assert(obj->is_objArray(), "expect object array"); + assert(obj->is_refArray(), "expect object array"); objArrayOop array = objArrayOop(obj); int len = array->length(); @@ -223,7 +223,7 @@ inline void ShenandoahMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, template inline void ShenandoahMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop obj, int chunk, int pow, bool weak) { - assert(obj->is_objArray(), "expect object array"); + assert(obj->is_refArray(), "expect object array"); objArrayOop array = objArrayOop(obj); assert (ObjArrayMarkingStride > 0, "sanity"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp index 68bec5c2071..d7f7bfa4236 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.inline.hpp @@ -179,7 +179,7 @@ void ShenandoahScanRemembered::process_clusters(size_t first_cluster, size_t cou // PREFIX: The object that straddles into this range of dirty cards // from the left may be subject to special treatment unless // it is an object array. - if (p < left && !obj->is_objArray()) { + if (p < left && !obj->is_refArray()) { // The mutator (both compiler and interpreter, but not JNI?) // typically dirty imprecisely (i.e. only the head of an object), // but GC closures typically dirty the object precisely. (It would @@ -253,7 +253,7 @@ void ShenandoahScanRemembered::process_clusters(size_t first_cluster, size_t cou assert(last_p < right, "Error"); // check if last_p suffix needs scanning const oop last_obj = cast_to_oop(last_p); - if (!last_obj->is_objArray()) { + if (!last_obj->is_refArray()) { // scan the remaining suffix of the object const MemRegion last_mr(right, p); assert(p == last_p + last_obj->size(), "Would miss portion of last_obj"); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index 5ab726e9d59..a055a99d463 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -455,7 +455,7 @@ template inline void ZBarrierSet::AccessBarrier::clone_in_heap(oop src, oop dst, size_t size) { check_is_valid_zaddress(src); - if (dst->is_objArray()) { + if (dst->is_refArray()) { // Cloning an object array is similar to performing array copy. // If an array is large enough to have its allocation segmented, // this operation might require GC barriers. However, the intrinsics diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index 63bede6143b..39b31bad38d 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -462,7 +462,7 @@ void ZHeapIterator::follow_array_chunk(const ZHeapIteratorContext& context, cons template void ZHeapIterator::follow(const ZHeapIteratorContext& context, oop obj) { // Follow - if (obj->is_objArray()) { + if (obj->is_refArray()) { follow_array(context, obj); } else { follow_object(context, obj); diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index fb20a424288..3a90b7c7672 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -29,6 +29,7 @@ #include "gc/z/zVerify.hpp" #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.hpp" +#include "oops/refArrayOop.hpp" #include "oops/oop.inline.hpp" inline bool ZIterator::is_invisible_object(oop obj) { @@ -45,7 +46,7 @@ inline bool ZIterator::is_invisible_object(oop obj) { } inline bool ZIterator::is_invisible_object_array(oop obj) { - return obj->klass()->is_objArray_klass() && is_invisible_object(obj); + return obj->klass()->is_refArray_klass() && is_invisible_object(obj); } // This iterator skips invisible object arrays @@ -68,7 +69,8 @@ void ZIterator::oop_iterate(oop obj, OopClosureT* cl) { template void ZIterator::oop_iterate_range(objArrayOop obj, OopClosureT* cl, int start, int end) { assert(!is_invisible_object_array(obj), "not safe"); - obj->oop_iterate_range(cl, start, end); + assert(obj->is_refArray(), "Must be"); + refArrayOop(obj)->oop_iterate_range(cl, start, end); } template diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 9846f1244ec..7e0d8e7de13 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -170,7 +170,7 @@ bool ZMark::follow_work_partial() { } bool ZMark::is_array(zaddress addr) const { - return to_oop(addr)->is_objArray(); + return to_oop(addr)->is_refArray(); } static uintptr_t encode_partial_array_offset(zpointer* addr) { diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index a9e65a9fd64..0bb3f271082 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -298,14 +298,14 @@ JRT_END JRT_ENTRY(void, InterpreterRuntime::flat_array_load(JavaThread* current, arrayOopDesc* array, int index)) assert(array->is_flatArray(), "Must be"); flatArrayOop farray = (flatArrayOop)array; - oop res = farray->read_value_from_flat_array(index, CHECK); + oop res = farray->obj_at(index, CHECK); current->set_vm_result_oop(res); JRT_END JRT_ENTRY(void, InterpreterRuntime::flat_array_store(JavaThread* current, oopDesc* val, arrayOopDesc* array, int index)) assert(array->is_flatArray(), "Must be"); flatArrayOop farray = (flatArrayOop)array; - farray->write_value_to_flat_array(val, index, CHECK); + farray->obj_at_put(index, val, CHECK); JRT_END JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* first_size_address)) diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index 25badd191a5..39f74c220d0 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -35,6 +35,7 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" #include "jfr/support/jfrThreadId.inline.hpp" #include "logging/log.hpp" +#include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceOop.hpp" #include "oops/klass.inline.hpp" @@ -186,7 +187,7 @@ static void array_construction(JfrJavaArguments* args, JavaValue* result, Instan Klass* const ak = klass->array_klass(THREAD); ObjArrayKlass::cast(ak)->initialize(THREAD); HandleMark hm(THREAD); - objArrayOop arr = ObjArrayKlass::cast(ak)->allocate(array_length, CHECK); + objArrayOop arr = oopFactory::new_objArray(klass, array_length, CHECK); result->set_oop(arr); } diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index a23b09c3c1e..1ec40195f4f 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1465,8 +1465,7 @@ JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) { JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) { JavaThread* THREAD = JavaThread::current(); // For exception macros. if (is_hotspot()) { - Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlass())->array_klass(CHECK_(JVMCIObject())); - objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject())); + objArrayOop result = oopFactory::new_objArray(Universe::byteArrayKlass(), length, CHECK_(JVMCIObject())); return wrap(result); } else { JNIAccessMark jni(this, THREAD); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index bccb5aca970..1d329b58e2e 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -783,6 +783,7 @@ declare_constant(Klass::_lh_array_tag_shift) \ declare_constant(Klass::_lh_array_tag_type_value) \ declare_constant(Klass::_lh_array_tag_obj_value) \ + declare_constant(Klass::_lh_array_tag_ref_value) \ \ declare_constant(markWord::no_hash) \ \ diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index 250191f4a8d..54cebb14469 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -41,6 +41,7 @@ #include "oops/instanceStackChunkKlass.inline.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/typeArrayKlass.inline.hpp" +#include "oops/refArrayKlass.inline.hpp" #include "utilities/debug.hpp" // Defaults to strong claiming. @@ -157,6 +158,7 @@ class OopOopIterateDispatch : public AllStatic { set_init_function(); set_init_function(); set_init_function(); + set_init_function(); } }; @@ -222,6 +224,7 @@ class OopOopIterateBoundedDispatch { set_init_function(); set_init_function(); set_init_function(); + set_init_function(); } }; @@ -287,6 +290,7 @@ class OopOopIterateBackwardsDispatch { set_init_function(); set_init_function(); set_init_function(); + set_init_function(); } }; diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp index fccb9a44185..d97ee67abf3 100644 --- a/src/hotspot/share/memory/oopFactory.cpp +++ b/src/hotspot/share/memory/oopFactory.cpp @@ -29,6 +29,7 @@ #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/arrayKlass.hpp" #include "oops/flatArrayKlass.hpp" #include "oops/flatArrayOop.inline.hpp" #include "oops/flatArrayOop.hpp" @@ -109,6 +110,39 @@ typeArrayOop oopFactory::new_typeArray_nozero(BasicType type, int length, TRAPS) return klass->allocate_common(length, false, THREAD); } +objArrayOop oopFactory::new_objArray2(Klass* klass, int length, ArrayKlass::ArrayProperties properties, TRAPS) { + assert(klass->is_klass(), "must be instance class"); + if (klass->is_array_klass()) { + assert(properties == ArrayKlass::ArrayProperties::DEFAULT, "properties only apply to single dimension arrays"); + return ArrayKlass::cast(klass)->allocate_arrayArray(1, length, THREAD); + } + if (klass->is_identity_class() || klass->is_abstract()) { + return InstanceKlass::cast(klass)->allocate_objArray(1, length, THREAD); + } else { + assert(!klass->is_identity_class() && !klass->is_abstract(), "Monomorphism required below"); + InlineKlass* vk = InlineKlass::cast(klass); + objArrayOop array = nullptr; + ArrayDescription ad = ObjArrayKlass::array_layout_selection(klass, properties); + switch (ad._kind) { + case Klass::RefArrayKlassKind: { + if (ArrayKlass::is_null_restricted(properties)) { + RefArrayKlass* array_klass = vk->null_free_reference_array(CHECK_NULL); + array = array_klass->allocate(length, CHECK_NULL); + } else { + array = InstanceKlass::cast(klass)->allocate_objArray(1, length, THREAD); + } + break; + } + case Klass::FlatArrayKlassKind: { + array = oopFactory::new_flatArray(vk, length, properties, ad._layout_kind, CHECK_NULL); + break; + } + default: + ShouldNotReachHere(); + } + return array; + } +} objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) { assert(klass->is_klass(), "must be instance class"); @@ -121,9 +155,9 @@ objArrayOop oopFactory::new_objArray(Klass* klass, int length, TRAPS) { objArrayOop oopFactory::new_null_free_objArray(Klass* k, int length, TRAPS) { InlineKlass* klass = InlineKlass::cast(k); - ObjArrayKlass* array_klass = klass->null_free_reference_array(CHECK_NULL); + RefArrayKlass* array_klass = klass->null_free_reference_array(CHECK_NULL); - assert(array_klass->is_objArray_klass(), "Must be"); + assert(array_klass->is_refArray_klass(), "Must be"); assert(array_klass->is_null_free_array_klass(), "Must be"); objArrayOop oop = array_klass->allocate(length, CHECK_NULL); @@ -134,13 +168,13 @@ objArrayOop oopFactory::new_null_free_objArray(Klass* k, int length, TRAPS) { return oop; } -flatArrayOop oopFactory::new_flatArray(Klass* k, int length, LayoutKind lk, TRAPS) { +flatArrayOop oopFactory::new_flatArray(Klass* k, int length, ArrayKlass::ArrayProperties props, LayoutKind lk, TRAPS) { InlineKlass* klass = InlineKlass::cast(k); - Klass* array_klass = klass->flat_array_klass(lk, CHECK_NULL); + Klass* array_klass = klass->flat_array_klass(props, lk, CHECK_NULL); assert(array_klass->is_flatArray_klass(), "Must be"); - flatArrayOop oop = FlatArrayKlass::cast(array_klass)->allocate(length, lk, CHECK_NULL); + flatArrayOop oop = (flatArrayOop)FlatArrayKlass::cast(array_klass)->allocate(length, lk, CHECK_NULL); assert(oop == nullptr || oop->is_flatArray(), "sanity"); assert(oop == nullptr || oop->klass()->is_flatArray_klass(), "sanity"); diff --git a/src/hotspot/share/memory/oopFactory.hpp b/src/hotspot/share/memory/oopFactory.hpp index 7676f1016f3..197a0525cd5 100644 --- a/src/hotspot/share/memory/oopFactory.hpp +++ b/src/hotspot/share/memory/oopFactory.hpp @@ -26,6 +26,7 @@ #define SHARE_MEMORY_OOPFACTORY_HPP #include "memory/referenceType.hpp" +#include "oops/arrayKlass.hpp" #include "oops/oopsHierarchy.hpp" #include "runtime/handles.hpp" #include "utilities/exceptions.hpp" @@ -55,6 +56,7 @@ class oopFactory: AllStatic { // Regular object arrays static objArrayOop new_objArray(Klass* klass, int length, TRAPS); + static objArrayOop new_objArray2(Klass* klass, int length, ArrayKlass::ArrayProperties properties, TRAPS); // Value arrays... // LWorld: @@ -63,7 +65,7 @@ class oopFactory: AllStatic { // // Method specifically null free and possibly flat if possible // i.e. flatArrayOop if flattening can be done, else "null free" objArrayOop - static flatArrayOop new_flatArray(Klass* klass, int length, LayoutKind lk, TRAPS); + static flatArrayOop new_flatArray(Klass* klass, int length, ArrayKlass::ArrayProperties props, LayoutKind lk, TRAPS); static objArrayOop new_null_free_objArray(Klass* klass, int length, TRAPS); // Helper conversions from value to obj array... diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 563861f18f8..6dd7c005979 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -115,7 +115,7 @@ static LatestMethodCache _value_object_hash_code_cache; // ValueObjectMethod // Known objects TypeArrayKlass* Universe::_typeArrayKlasses[T_LONG+1] = { nullptr /*, nullptr...*/ }; -ObjArrayKlass* Universe::_objectArrayKlass = nullptr; +RefArrayKlass* Universe::_objectArrayKlass = nullptr; Klass* Universe::_fillerArrayKlass = nullptr; OopHandle Universe::_basic_type_mirrors[T_VOID+1]; #if INCLUDE_CDS_JAVA_HEAP @@ -503,7 +503,7 @@ void Universe::genesis(TRAPS) { // for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl. { Klass* oak = vmClasses::Object_klass()->array_klass(CHECK); - _objectArrayKlass = ObjArrayKlass::cast(oak); + _objectArrayKlass = RefArrayKlass::cast(oak); } // OLD // Add the class to the class hierarchy manually to make sure that diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index 6a98ce1ec78..1ddb50a52ab 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -29,6 +29,7 @@ #include "memory/reservedSpace.hpp" #include "oops/array.hpp" #include "oops/oopHandle.hpp" +#include "oops/refArrayKlass.hpp" #include "runtime/handles.hpp" #include "utilities/growableArray.hpp" @@ -65,7 +66,7 @@ class Universe: AllStatic { private: // Known classes in the VM static TypeArrayKlass* _typeArrayKlasses[T_LONG+1]; - static ObjArrayKlass* _objectArrayKlass; + static RefArrayKlass* _objectArrayKlass; // Special int-Array that represents filler objects that are used by GC to overwrite // dead objects. References to them are generally an error. static Klass* _fillerArrayKlass; @@ -186,7 +187,7 @@ class Universe: AllStatic { static TypeArrayKlass* floatArrayKlass() { return typeArrayKlass(T_FLOAT); } static TypeArrayKlass* doubleArrayKlass() { return typeArrayKlass(T_DOUBLE); } - static ObjArrayKlass* objectArrayKlass() { return _objectArrayKlass; } + static RefArrayKlass* objectArrayKlass() { return _objectArrayKlass; } static Klass* fillerArrayKlass() { return _fillerArrayKlass; } diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index 462f624e3b2..6c2c0ce1b45 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -41,6 +41,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" +#include "oops/refArrayKlass.hpp" #include "runtime/handles.inline.hpp" void* ArrayKlass::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw() { @@ -94,9 +95,10 @@ Method* ArrayKlass::uncached_lookup_method(const Symbol* name, return super()->uncached_lookup_method(name, signature, OverpassLookupMode::skip, private_mode); } -ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind, markWord prototype_header) : +ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind, ArrayProperties props, markWord prototype_header) : Klass(kind, prototype_header), _dimension(1), + _properties(props), _higher_dimension(nullptr), _lower_dimension(nullptr) { // Arrays don't add any new methods, so their vtable is the same size as @@ -159,8 +161,8 @@ ArrayKlass* ArrayKlass::array_klass(int n, TRAPS) { 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, CHECK_NULL); + ObjArrayKlass* ak = nullptr; + ak = RefArrayKlass::allocate_refArray_klass(class_loader_data(), dim + 1, this, ArrayKlass::ArrayProperties::DEFAULT, CHECK_NULL); // use 'release' to pair with lock-free load release_set_higher_dimension(ak); assert(ak->lower_dimension() == this, "lower dimension mismatch"); @@ -210,7 +212,7 @@ GrowableArray* ArrayKlass::compute_secondary_supers(int num_extra_slots, objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) { check_array_allocation_length(length, arrayOopDesc::max_array_length(T_ARRAY), CHECK_NULL); - size_t size = objArrayOopDesc::object_size(length); + size_t size = refArrayOopDesc::object_size(length); ArrayKlass* ak = array_klass(n + dimension(), CHECK_NULL); objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length, /* do_zero */ true, CHECK_NULL); diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index e94dbe187c9..f3e5695c693 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -35,25 +35,33 @@ class ObjArrayKlass; class ArrayKlass: public Klass { friend class VMStructs; + + public: + enum ArrayProperties : uint32_t { + DEFAULT = 0, + NULL_RESTRICTED = 1 << 0, + NON_ATOMIC = 1 << 1, + // FINAL = 1 << 2, + // VOLATILE = 1 << 3 + DUMMY = 1 << 4 // Just to transition the code, to be removed ASAP + }; + + static bool is_null_restricted(ArrayProperties props) { return (props & NULL_RESTRICTED) != 0; } + static bool is_non_atomic(ArrayProperties props) { return (props & NON_ATOMIC) != 0; } + private: // If you add a new field that points to any metaspace object, you // must add this field to ArrayKlass::metaspace_pointers_do(). int _dimension; // This is n'th-dimensional array. + ArrayProperties _properties; ObjArrayKlass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). ArrayKlass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). protected: - Klass* _element_klass; // The klass of the elements of this array type - // The element type must be registered for both object arrays - // (incl. object arrays with value type elements) and value type - // arrays containing flat value types. However, the element - // type must not be registered for arrays of primitive types. - // TODO: Update the class hierarchy so that element klass appears - // only in array that contain non-primitive types. // Constructors // The constructor with the Symbol argument does the real array // initialization, the other is a dummy - ArrayKlass(Symbol* name, KlassKind kind, markWord prototype_header = markWord::prototype()); + ArrayKlass(Symbol* name, KlassKind kind, ArrayProperties props, markWord prototype_header = markWord::prototype()); ArrayKlass(); // Create array_name for element klass @@ -62,12 +70,6 @@ class ArrayKlass: public Klass { void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw(); public: - // Instance variables - virtual Klass* element_klass() const { return _element_klass; } - virtual void set_element_klass(Klass* k) { _element_klass = k; } - - // Compiler/Interpreter offset - static ByteSize element_klass_offset() { return in_ByteSize(offset_of(ArrayKlass, _element_klass)); } // Testing operation DEBUG_ONLY(bool is_array_klass_slow() const { return true; }) @@ -161,4 +163,12 @@ class ArrayKlass: public Klass { void oop_verify_on(oop obj, outputStream* st); }; +class ArrayDescription : public StackObj { + public: + Klass::KlassKind _kind; + ArrayKlass::ArrayProperties _properties; + LayoutKind _layout_kind; + ArrayDescription(Klass::KlassKind k, ArrayKlass::ArrayProperties p, LayoutKind lk) { _kind = k; _properties = p; _layout_kind = lk; } + }; + #endif // SHARE_OOPS_ARRAYKLASS_HPP diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 6619c0c58c2..9337af44633 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -59,6 +59,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/refArrayOop.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/atomic.hpp" @@ -192,7 +193,8 @@ oop ConstantPool::resolved_reference_at(int index) const { // Use a CAS for multithreaded access oop ConstantPool::set_resolved_reference_at(int index, oop new_result) { assert(oopDesc::is_oop_or_null(new_result), "Must be oop"); - return resolved_references()->replace_if_null(index, new_result); + // return resolved_references()->replace_if_null(index, new_result); + return refArrayOopDesc::cast(resolved_references())->replace_if_null(index, new_result); } // Create resolved_references array and mapping array for original cp indexes @@ -513,6 +515,7 @@ static const char* get_type(Klass* k) { if (src_k->is_objArray_klass()) { src_k = ObjArrayKlass::cast(src_k)->bottom_klass(); assert(!src_k->is_objArray_klass(), "sanity"); + assert(src_k->is_instance_klass() || src_k->is_typeArray_klass(), "Sanity check"); } if (src_k->is_typeArray_klass()) { diff --git a/src/hotspot/share/oops/flatArrayKlass.cpp b/src/hotspot/share/oops/flatArrayKlass.cpp index 0f19c32936b..253ac9b2833 100644 --- a/src/hotspot/share/oops/flatArrayKlass.cpp +++ b/src/hotspot/share/oops/flatArrayKlass.cpp @@ -54,7 +54,8 @@ // Allocation... -FlatArrayKlass::FlatArrayKlass(Klass* element_klass, Symbol* name, LayoutKind lk) : ArrayKlass(name, Kind, markWord::flat_array_prototype(lk)) { +FlatArrayKlass::FlatArrayKlass(Klass* element_klass, Symbol* name, ArrayProperties props, LayoutKind lk) : + ObjArrayKlass(1, element_klass, name, Kind, props, markWord::flat_array_prototype(lk)) { assert(element_klass->is_inline_klass(), "Expected Inline"); assert(lk == LayoutKind::NON_ATOMIC_FLAT || lk == LayoutKind::ATOMIC_FLAT || lk == LayoutKind::NULLABLE_ATOMIC_FLAT, "Must be a flat layout"); @@ -94,7 +95,7 @@ FlatArrayKlass::FlatArrayKlass(Klass* element_klass, Symbol* name, LayoutKind lk #endif } -FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, LayoutKind lk, TRAPS) { +FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, ArrayProperties props, LayoutKind lk, TRAPS) { guarantee((!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()), "Really ?!"); assert(UseArrayFlattening, "Flatten array required"); assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping"); @@ -121,7 +122,7 @@ FlatArrayKlass* FlatArrayKlass::allocate_klass(Klass* eklass, LayoutKind lk, TRA Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, CHECK_NULL); ClassLoaderData* loader_data = element_klass->class_loader_data(); int size = ArrayKlass::static_size(FlatArrayKlass::header_size()); - FlatArrayKlass* vak = new (loader_data, size, THREAD) FlatArrayKlass(element_klass, name, lk); + FlatArrayKlass* vak = new (loader_data, size, THREAD) FlatArrayKlass(element_klass, name, props, lk); ModuleEntry* module = vak->module(); assert(module != nullptr, "No module entry for array"); @@ -142,7 +143,7 @@ void FlatArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) { } // Oops allocation... -flatArrayOop FlatArrayKlass::allocate(int length, LayoutKind lk, TRAPS) { +objArrayOop FlatArrayKlass::allocate(int length, LayoutKind lk, TRAPS) { check_array_allocation_length(length, max_elements(), CHECK_NULL); int size = flatArrayOopDesc::object_size(layout_helper(), length); flatArrayOop array = (flatArrayOop) Universe::heap()->array_allocate(this, size, length, true, CHECK_NULL); @@ -159,7 +160,7 @@ jint FlatArrayKlass::array_layout_helper(InlineKlass* vk, LayoutKind lk) { int esize = log2i_exact(round_up_power_of_2(vk->layout_size_in_bytes(lk))); int hsize = arrayOopDesc::base_offset_in_bytes(etype); bool null_free = lk != LayoutKind::NULLABLE_ATOMIC_FLAT; - int lh = Klass::array_layout_helper(_lh_array_tag_vt_value, null_free, hsize, etype, esize); + int lh = Klass::array_layout_helper(_lh_array_tag_flat_value, null_free, hsize, etype, esize); assert(lh < (int)_lh_neutral_value, "must look like an array layout"); assert(layout_helper_is_array(lh), "correct kind"); @@ -232,8 +233,8 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos, if (length == 0) return; - ArrayKlass* sk = ArrayKlass::cast(s->klass()); - ArrayKlass* dk = ArrayKlass::cast(d->klass()); + ObjArrayKlass* sk = ObjArrayKlass::cast(s->klass()); + ObjArrayKlass* dk = ObjArrayKlass::cast(d->klass()); Klass* d_elem_klass = dk->element_klass(); Klass* s_elem_klass = sk->element_klass(); /**** CMH: compare and contrast impl, re-factor once we find edge cases... ****/ @@ -311,13 +312,13 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos, } } } else { // flatArray-to-objArray - assert(dk->is_objArray_klass(), "Expected objArray here"); + assert(dk->is_refArray_klass(), "Expected objArray here"); // Need to allocate each new src elem payload -> dst oop objArrayHandle dh(THREAD, (objArrayOop)d); flatArrayHandle sh(THREAD, sa); InlineKlass* vk = InlineKlass::cast(s_elem_klass); for (int i = 0; i < length; i++) { - oop o = sh->read_value_from_flat_array(src_pos + i, CHECK); + oop o = sh->obj_at(src_pos + i, CHECK); dh->obj_at_put(dst_pos + i, o); } } @@ -331,7 +332,7 @@ void FlatArrayKlass::copy_array(arrayOop s, int src_pos, InlineKlass* vk = InlineKlass::cast(d_elem_klass); for (int i = 0; i < length; i++) { - da->write_value_to_flat_array(sa->obj_at(src_pos + i), dst_pos + i, CHECK); + da->obj_at_put( dst_pos + i, sa->obj_at(src_pos + i), CHECK); } } } @@ -384,7 +385,7 @@ u2 FlatArrayKlass::compute_modifier_flags() const { void FlatArrayKlass::print_on(outputStream* st) const { #ifndef PRODUCT - assert(!is_objArray_klass(), "Unimplemented"); + assert(!is_refArray_klass(), "Unimplemented"); st->print("Flat Type Array: "); Klass::print_on(st); diff --git a/src/hotspot/share/oops/flatArrayKlass.hpp b/src/hotspot/share/oops/flatArrayKlass.hpp index ca02351e99d..256107bc83f 100644 --- a/src/hotspot/share/oops/flatArrayKlass.hpp +++ b/src/hotspot/share/oops/flatArrayKlass.hpp @@ -28,12 +28,13 @@ #include "classfile/classLoaderData.hpp" #include "oops/arrayKlass.hpp" #include "oops/inlineKlass.hpp" +#include "oops/objArrayKlass.hpp" #include "utilities/macros.hpp" /** * Array of inline types, gives a layout of typeArrayOop, but needs oops iterators */ -class FlatArrayKlass : public ArrayKlass { +class FlatArrayKlass : public ObjArrayKlass { friend class VMStructs; public: @@ -41,7 +42,7 @@ class FlatArrayKlass : public ArrayKlass { private: // Constructor - FlatArrayKlass(Klass* element_klass, Symbol* name, LayoutKind lk); + FlatArrayKlass(Klass* element_klass, Symbol* name, ArrayProperties props, LayoutKind lk); LayoutKind _layout_kind; @@ -50,7 +51,7 @@ class FlatArrayKlass : public ArrayKlass { FlatArrayKlass() {} // used by CppVtableCloner::initialize() InlineKlass* element_klass() const { return InlineKlass::cast(_element_klass); } - void set_element_klass(Klass* k) { _element_klass = k; } + void set_element_klass(Klass* k) { assert(k->is_inline_klass(), "Must be"); _element_klass = k; } LayoutKind layout_kind() const { return _layout_kind; } void set_layout_kind(LayoutKind lk) { _layout_kind = lk; } @@ -63,7 +64,7 @@ class FlatArrayKlass : public ArrayKlass { } // klass allocation - static FlatArrayKlass* allocate_klass(Klass* element_klass, LayoutKind lk, TRAPS); + static FlatArrayKlass* allocate_klass(Klass* element_klass, ArrayProperties props, LayoutKind lk, TRAPS); void initialize(TRAPS); @@ -97,7 +98,7 @@ class FlatArrayKlass : public ArrayKlass { size_t oop_size(oop obj) const; // Oop Allocation - flatArrayOop allocate(int length, LayoutKind lk, TRAPS); + objArrayOop allocate(int length, LayoutKind lk, TRAPS); oop multi_allocate(int rank, jint* sizes, TRAPS); // Naming diff --git a/src/hotspot/share/oops/flatArrayOop.hpp b/src/hotspot/share/oops/flatArrayOop.hpp index 500e98f6dbc..7f0a603eb7b 100644 --- a/src/hotspot/share/oops/flatArrayOop.hpp +++ b/src/hotspot/share/oops/flatArrayOop.hpp @@ -28,19 +28,22 @@ #include "oops/arrayOop.hpp" #include "oops/inlineKlass.hpp" #include "oops/klass.hpp" +#include "oops/objArrayOop.hpp" #include "runtime/handles.hpp" // A flatArrayOop points to a flat array containing inline types (no indirection). // It may include embedded oops in its elements. -class flatArrayOopDesc : public arrayOopDesc { +class flatArrayOopDesc : public objArrayOopDesc { public: void* base() const; void* value_at_addr(int index, jint lh) const; - inline oop read_value_from_flat_array( int index, TRAPS); - inline void write_value_to_flat_array(oop value, int index, TRAPS); + inline oop obj_at(int index) const; + inline oop obj_at(int index, TRAPS) const; + inline void obj_at_put(int index, oop value); + inline void obj_at_put(int index, oop value, TRAPS); // Sizing static size_t element_size(int lh, int nof_elements) { @@ -49,7 +52,7 @@ class flatArrayOopDesc : public arrayOopDesc { } static int object_size(int lh, int length) { - julong size_in_bytes = base_offset_in_bytes(Klass::layout_helper_element_type(lh)); + julong size_in_bytes = arrayOopDesc::base_offset_in_bytes(Klass::layout_helper_element_type(lh)); size_in_bytes += element_size(lh, length); julong size_in_words = ((size_in_bytes + (HeapWordSize-1)) >> LogHeapWordSize); assert(size_in_words <= (julong)max_jint, "no overflow"); @@ -60,4 +63,7 @@ class flatArrayOopDesc : public arrayOopDesc { }; +// See similar requirement for oopDesc. +static_assert(std::is_trivially_default_constructible::value, "required"); + #endif // SHARE_VM_OOPS_FLATARRAYOOP_HPP diff --git a/src/hotspot/share/oops/flatArrayOop.inline.hpp b/src/hotspot/share/oops/flatArrayOop.inline.hpp index d6eee2dcc53..b491d5089ce 100644 --- a/src/hotspot/share/oops/flatArrayOop.inline.hpp +++ b/src/hotspot/share/oops/flatArrayOop.inline.hpp @@ -46,23 +46,35 @@ inline int flatArrayOopDesc::object_size() const { return object_size(klass()->layout_helper(), length()); } -inline oop flatArrayOopDesc::read_value_from_flat_array(int index, TRAPS) { - // This method assumes that the validity of the index has already been checked +inline oop flatArrayOopDesc::obj_at(int index) const { + EXCEPTION_MARK; + return obj_at(index, THREAD); +} + +inline oop flatArrayOopDesc::obj_at(int index, TRAPS) const { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); FlatArrayKlass* faklass = FlatArrayKlass::cast(klass()); InlineKlass* vk = InlineKlass::cast(faklass->element_klass()); int offset = ((char*)value_at_addr(index, faklass->layout_helper())) - ((char*)(oopDesc*)this); - oop res = vk->read_payload_from_addr(this, offset, faklass->layout_kind(), CHECK_NULL); + oop res = vk->read_payload_from_addr((oopDesc*)this, offset, faklass->layout_kind(), CHECK_NULL); return res; } -inline void flatArrayOopDesc::write_value_to_flat_array(oop value, int index, TRAPS) { - // This method assumes that the validity of the index has already been checked +inline void flatArrayOopDesc::obj_at_put(int index, oop value) { + EXCEPTION_MARK; // What if the caller is not a Java Thread? + obj_at_put(index, value, THREAD); +} + +inline void flatArrayOopDesc::obj_at_put(int index, oop value, TRAPS) { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); FlatArrayKlass* faklass = FlatArrayKlass::cast(klass()); InlineKlass* vk = InlineKlass::cast(faklass->element_klass()); if (value != nullptr) { if (value->klass() != vk) { THROW(vmSymbols::java_lang_ArrayStoreException()); } + } else if(is_null_free_array()) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Cannot store null in a null-restricted array"); } vk->write_value_to_addr(value, value_at_addr(index, faklass->layout_helper()), faklass->layout_kind(), true, CHECK); } diff --git a/src/hotspot/share/oops/inlineKlass.cpp b/src/hotspot/share/oops/inlineKlass.cpp index 0996a3d44ec..0d12415803d 100644 --- a/src/hotspot/share/oops/inlineKlass.cpp +++ b/src/hotspot/share/oops/inlineKlass.cpp @@ -34,6 +34,7 @@ #include "memory/metaspaceClosure.hpp" #include "memory/metadataFactory.hpp" #include "oops/access.hpp" +#include "oops/arrayKlass.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/fieldStreams.inline.hpp" #include "oops/flatArrayKlass.hpp" @@ -42,6 +43,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/refArrayKlass.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/safepointVerifiers.hpp" @@ -227,7 +229,7 @@ void InlineKlass::copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool } } -oop InlineKlass::read_payload_from_addr(oop src, int offset, LayoutKind lk, TRAPS) { +oop InlineKlass::read_payload_from_addr(const oop src, int offset, LayoutKind lk, TRAPS) { assert(src != nullptr, "Must be"); assert(is_layout_supported(lk), "Unsupported layout"); switch(lk) { @@ -299,15 +301,15 @@ bool InlineKlass::maybe_flat_in_array() { return true; } -ObjArrayKlass* InlineKlass::null_free_reference_array(TRAPS) { +RefArrayKlass* InlineKlass::null_free_reference_array(TRAPS) { if (Atomic::load_acquire(adr_null_free_reference_array_klass()) == nullptr) { // Atomic creation of array_klasses RecursiveLocker rl(MultiArray_lock, THREAD); // Check if update has already taken place if (null_free_reference_array_klass() == nullptr) { - ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, true, CHECK_NULL); - + RefArrayKlass* k = nullptr; + k = RefArrayKlass::allocate_refArray_klass(class_loader_data(), 1, this, ArrayKlass::ArrayProperties::NULL_RESTRICTED, CHECK_NULL); // use 'release' to pair with lock-free load Atomic::release_store(adr_null_free_reference_array_klass(), k); } @@ -317,7 +319,7 @@ ObjArrayKlass* InlineKlass::null_free_reference_array(TRAPS) { // There's no reason for this method to have a TRAP argument -FlatArrayKlass* InlineKlass::flat_array_klass(LayoutKind lk, TRAPS) { +FlatArrayKlass* InlineKlass::flat_array_klass(ArrayKlass::ArrayProperties props, LayoutKind lk, TRAPS) { FlatArrayKlass* volatile* adr_flat_array_klass = nullptr; switch(lk) { case LayoutKind::NON_ATOMIC_FLAT: @@ -341,7 +343,7 @@ FlatArrayKlass* InlineKlass::flat_array_klass(LayoutKind lk, TRAPS) { RecursiveLocker rl(MultiArray_lock, THREAD); if (*adr_flat_array_klass == nullptr) { - FlatArrayKlass* k = FlatArrayKlass::allocate_klass(this, lk, CHECK_NULL); + FlatArrayKlass* k = FlatArrayKlass::allocate_klass(this, props, lk, CHECK_NULL); Atomic::release_store(adr_flat_array_klass, k); } } diff --git a/src/hotspot/share/oops/inlineKlass.hpp b/src/hotspot/share/oops/inlineKlass.hpp index e6c1e93ce6e..863d7ca7ae5 100644 --- a/src/hotspot/share/oops/inlineKlass.hpp +++ b/src/hotspot/share/oops/inlineKlass.hpp @@ -27,6 +27,7 @@ #include "classfile/classFileParser.hpp" #include "classfile/javaClasses.hpp" +#include "oops/arrayKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/method.hpp" #include "runtime/registerMap.hpp" @@ -107,12 +108,12 @@ class InlineKlass: public InstanceKlass { return *adr_nullable_atomic_flat_array_klass(); } - ObjArrayKlass* volatile* adr_null_free_reference_array_klass() const { + RefArrayKlass* volatile* adr_null_free_reference_array_klass() const { assert(_adr_inlineklass_fixed_block != nullptr, "Should have been initialized"); - return (ObjArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _null_free_reference_array_klass)); + return (RefArrayKlass* volatile*) ((address)_adr_inlineklass_fixed_block) + in_bytes(byte_offset_of(InlineKlassFixedBlock, _null_free_reference_array_klass)); } - ObjArrayKlass* null_free_reference_array_klass() const { + RefArrayKlass* null_free_reference_array_klass() const { return *adr_null_free_reference_array_klass(); } @@ -264,9 +265,9 @@ class InlineKlass: public InstanceKlass { // null free inline arrays... // - FlatArrayKlass* flat_array_klass(LayoutKind lk, TRAPS); + FlatArrayKlass* flat_array_klass(ArrayKlass::ArrayProperties props, LayoutKind lk, TRAPS); FlatArrayKlass* flat_array_klass_or_null(LayoutKind lk); - ObjArrayKlass* null_free_reference_array(TRAPS); + RefArrayKlass* null_free_reference_array(TRAPS); // Methods to copy payload between containers // Methods taking a LayoutKind argument expect that both the source and the destination @@ -275,7 +276,7 @@ class InlineKlass: public InstanceKlass { // is compatible with all the other layouts. void write_value_to_addr(oop src, void* dst, LayoutKind lk, bool dest_is_initialized, TRAPS); - oop read_payload_from_addr(oop src, int offset, LayoutKind lk, TRAPS); + oop read_payload_from_addr(const oop src, int offset, LayoutKind lk, TRAPS); void copy_payload_to_addr(void* src, void* dst, LayoutKind lk, bool dest_is_initialized); // oop iterate raw inline type data pointer (where oop_addr may not be an oop, but backing/array-element) diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index a424cd38e02..1b1b73dbd8a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -75,6 +75,7 @@ #include "oops/recordComponent.hpp" #include "oops/symbol.hpp" #include "oops/inlineKlass.hpp" +#include "oops/refArrayKlass.hpp" #include "prims/jvmtiExport.hpp" #include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiThreadState.hpp" @@ -1745,7 +1746,7 @@ bool InstanceKlass::is_same_or_direct_interface(Klass *k) const { objArrayOop InstanceKlass::allocate_objArray(int n, int length, TRAPS) { check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL); - size_t size = objArrayOopDesc::object_size(length); + size_t size = refArrayOopDesc::object_size(length); ArrayKlass* ak = array_klass(n, CHECK_NULL); objArrayOop o = (objArrayOop)Universe::heap()->array_allocate(ak, size, length, /* do_zero */ true, CHECK_NULL); @@ -1812,7 +1813,8 @@ ArrayKlass* InstanceKlass::array_klass(int n, TRAPS) { // Check if another thread created the array klass while we were waiting for the lock. if (array_klasses() == nullptr) { - ObjArrayKlass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, false, CHECK_NULL); + ObjArrayKlass* k = nullptr; + k = RefArrayKlass::allocate_refArray_klass(class_loader_data(), 1, this, ArrayKlass::ArrayProperties::DEFAULT, CHECK_NULL); // use 'release' to pair with lock-free load release_set_array_klasses(k); } diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index fd2bd6491f8..97f570e8451 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -33,6 +33,7 @@ #include "oops/fieldInfo.hpp" #include "oops/instanceKlassFlags.hpp" #include "oops/instanceOop.hpp" +#include "oops/refArrayKlass.hpp" #include "runtime/handles.hpp" #include "runtime/javaThread.hpp" #include "utilities/accessFlags.hpp" @@ -149,7 +150,7 @@ class InlineKlassFixedBlock { FlatArrayKlass* _non_atomic_flat_array_klass; FlatArrayKlass* _atomic_flat_array_klass; FlatArrayKlass* _nullable_atomic_flat_array_klass; - ObjArrayKlass* _null_free_reference_array_klass; + RefArrayKlass* _null_free_reference_array_klass; int _payload_offset; // offset of the begining of the payload in a heap buffered instance int _payload_size_in_bytes; // size of payload layout int _payload_alignment; // alignment required for payload diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 054e37485f8..ff5da202006 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -297,12 +297,12 @@ jint Klass::array_layout_helper(BasicType etype) { int hsize = arrayOopDesc::base_offset_in_bytes(etype); int esize = type2aelembytes(etype); bool isobj = (etype == T_OBJECT); - int tag = isobj ? _lh_array_tag_obj_value : _lh_array_tag_type_value; + int tag = isobj ? _lh_array_tag_ref_value : _lh_array_tag_type_value; int lh = array_layout_helper(tag, false, hsize, etype, exact_log2(esize)); assert(lh < (int)_lh_neutral_value, "must look like an array layout"); assert(layout_helper_is_array(lh), "correct kind"); - assert(layout_helper_is_objArray(lh) == isobj, "correct kind"); + assert(layout_helper_is_refArray(lh) == isobj, "correct kind"); assert(layout_helper_is_typeArray(lh) == !isobj, "correct kind"); assert(layout_helper_header_size(lh) == hsize, "correct decode"); assert(layout_helper_element_type(lh) == etype, "correct decode"); diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index feb9e888dd2..ff3d4f406e8 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -66,20 +66,22 @@ class Klass : public Metadata { friend class JVMCIVMStructs; public: // Klass Kinds for all subclasses of Klass - enum KlassKind : u2 { - InstanceKlassKind, - InlineKlassKind, - InstanceRefKlassKind, - InstanceMirrorKlassKind, - InstanceClassLoaderKlassKind, - InstanceStackChunkKlassKind, - TypeArrayKlassKind, - FlatArrayKlassKind, - ObjArrayKlassKind, - UnknownKlassKind - }; - - static const uint KLASS_KIND_COUNT = ObjArrayKlassKind + 1; + enum KlassKind : u2 + { + InstanceKlassKind, + InlineKlassKind, + InstanceRefKlassKind, + InstanceMirrorKlassKind, + InstanceClassLoaderKlassKind, + InstanceStackChunkKlassKind, + TypeArrayKlassKind, + ObjArrayKlassKind, + RefArrayKlassKind, + FlatArrayKlassKind, + UnknownKlassKind + }; + + static const uint KLASS_KIND_COUNT = FlatArrayKlassKind + 1; protected: // If you add a new field that points to any metaspace object, you @@ -463,18 +465,19 @@ class Klass : public Metadata { static const int _lh_element_type_mask = right_n_bits(BitsPerByte); // shifted mask static const int _lh_header_size_shift = BitsPerByte*2; static const int _lh_header_size_mask = right_n_bits(BitsPerByte); // shifted mask - static const int _lh_array_tag_bits = 3; + static const int _lh_array_tag_bits = 4; static const int _lh_array_tag_shift = BitsPerInt - _lh_array_tag_bits; static const unsigned int _lh_array_tag_type_value = 0Xfffffffc; - static const unsigned int _lh_array_tag_vt_value = 0Xfffffffd; - static const unsigned int _lh_array_tag_obj_value = 0Xfffffffe; + static const unsigned int _lh_array_tag_flat_value = 0Xfffffffa; + static const unsigned int _lh_array_tag_ref_value = 0Xfffffff8; + static const unsigned int _lh_array_tag_obj_value = 0Xfffffff9; // null-free array flag bit under the array tag bits, shift one more to get array tag value static const int _lh_null_free_shift = _lh_array_tag_shift - 1; static const int _lh_null_free_mask = 1; - static const jint _lh_array_tag_flat_value_bit_inplace = (jint) (1 << _lh_array_tag_shift); + static const jint _lh_array_tag_flat_value_bit_inplace = (jint) (1 << (_lh_array_tag_shift + 1)); static int layout_helper_size_in_bytes(jint lh) { assert(lh > (jint)_lh_neutral_value, "must be instance"); @@ -496,11 +499,14 @@ class Klass : public Metadata { static bool layout_helper_is_objArray(jint lh) { return (juint)_lh_array_tag_obj_value == (juint)(lh >> _lh_array_tag_shift); } + static bool layout_helper_is_refArray(jint lh) { + return (juint)_lh_array_tag_ref_value == (juint)(lh >> _lh_array_tag_shift); + } static bool layout_helper_is_flatArray(jint lh) { - return (juint)_lh_array_tag_vt_value == (juint)(lh >> _lh_array_tag_shift); + return (juint)_lh_array_tag_flat_value == (juint)(lh >> _lh_array_tag_shift); } static bool layout_helper_is_null_free(jint lh) { - assert(layout_helper_is_flatArray(lh) || layout_helper_is_objArray(lh), "must be array of inline types"); + assert(layout_helper_is_flatArray(lh) || layout_helper_is_refArray(lh), "must be array of inline types"); return ((lh >> _lh_null_free_shift) & _lh_null_free_mask); } static jint layout_helper_set_null_free(jint lh) { @@ -687,6 +693,7 @@ class Klass : public Metadata { virtual bool is_instance_klass_slow() const { return false; } virtual bool is_array_klass_slow() const { return false; } virtual bool is_objArray_klass_slow() const { return false; } + virtual bool is_refArray_klass_slow() const { return false; } virtual bool is_typeArray_klass_slow() const { return false; } virtual bool is_flatArray_klass_slow() const { return false; } #endif // ASSERT @@ -714,7 +721,8 @@ class Klass : public Metadata { bool is_array_klass() const { return assert_same_query( _kind >= TypeArrayKlassKind, is_array_klass_slow()); } bool is_stack_chunk_instance_klass() const { return _kind == InstanceStackChunkKlassKind; } bool is_flatArray_klass() const { return assert_same_query( _kind == FlatArrayKlassKind, is_flatArray_klass_slow()); } - bool is_objArray_klass() const { return assert_same_query( _kind == ObjArrayKlassKind, is_objArray_klass_slow()); } + bool is_objArray_klass() const { return assert_same_query( _kind == ObjArrayKlassKind || _kind == RefArrayKlassKind || _kind == FlatArrayKlassKind, is_objArray_klass_slow()); } + bool is_refArray_klass() const { return assert_same_query( _kind == RefArrayKlassKind, is_refArray_klass_slow()); } bool is_typeArray_klass() const { return assert_same_query( _kind == TypeArrayKlassKind, is_typeArray_klass_slow()); } #undef assert_same_query diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 39ede65efe0..09d3f97d101 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -35,32 +35,34 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "oops/arrayKlass.hpp" +#include "oops/flatArrayKlass.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/markWord.hpp" #include "oops/objArrayKlass.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/refArrayKlass.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, bool null_free, + Klass* k, Symbol* name, ArrayKlass::ArrayProperties props, 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); + return new (loader_data, size, THREAD) ObjArrayKlass(n, k, name, Kind, props, ArrayKlass::is_null_restricted(props) ? markWord::null_free_array_prototype() : markWord::prototype()); } 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"); + ArrayKlass::ArrayProperties props, TRAPS) { + assert(!ArrayKlass::is_null_restricted(props) || (n == 1 && element_klass->is_inline_klass()), "null-free unsupported"); // Eagerly allocate the direct array supertype. Klass* super_klass = nullptr; @@ -71,7 +73,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da // 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) { + if (ArrayKlass::is_null_restricted(props)) { super_klass = element_klass->array_klass(CHECK_NULL); } else { super_klass = element_super->array_klass(CHECK_NULL); @@ -92,7 +94,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da 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); + ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, props, CHECK_NULL); ModuleEntry* module = oak->module(); assert(module != nullptr, "No module entry for array"); @@ -110,17 +112,18 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da return oak; } -ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool null_free) : -ArrayKlass(name, Kind, null_free ? markWord::null_free_array_prototype() : markWord::prototype()) { +ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, KlassKind kind, ArrayKlass::ArrayProperties props, markWord mk) : +ArrayKlass(name, kind, props, mk) { set_dimension(n); set_element_klass(element_klass); Klass* bk; - if (element_klass->is_objArray_klass()) { + if (element_klass->is_refArray_klass()) { bk = ObjArrayKlass::cast(element_klass)->bottom_klass(); } else if (element_klass->is_flatArray_klass()) { - bk = FlatArrayKlass::cast(element_klass)->element_klass(); + bk = FlatArrayKlass::cast(element_klass)->element_klass(); // flat array case should be merge with refArray case once reparented } else { + assert(!element_klass->is_objArray_klass(), "Sanity"); bk = element_klass; } assert(bk != nullptr && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass"); @@ -132,7 +135,7 @@ ArrayKlass(name, Kind, null_free ? markWord::null_free_array_prototype() : markW } int lh = array_layout_helper(T_OBJECT); - if (null_free) { + if (ArrayKlass::is_null_restricted(props)) { assert(n == 1, "Bytecode does not support null-free multi-dim"); lh = layout_helper_set_null_free(lh); #ifdef _LP64 @@ -149,23 +152,49 @@ size_t ObjArrayKlass::oop_size(oop obj) const { // because size_given_klass() calls oop_size() on objects that might be // concurrently forwarded, which would overwrite the Klass*. assert(UseCompactObjectHeaders || obj->is_objArray(), "must be object array"); - return objArrayOop(obj)->object_size(); + // return objArrayOop(obj)->object_size(); + return obj->is_flatArray() ? flatArrayOop(obj)->object_size() : refArrayOop(obj)->object_size(); } -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); - objArrayOop array = (objArrayOop)Universe::heap()->array_allocate(this, size, length, - /* do_zero */ true, CHECK_NULL); - objArrayHandle array_h(THREAD, array); - return array_h(); +ArrayDescription ObjArrayKlass::array_layout_selection(Klass* element, ArrayProperties properties) { + if (element->is_identity_class() || element->is_abstract()) { + return ArrayDescription(RefArrayKlassKind, properties, LayoutKind::REFERENCE); + } + assert(element->is_final(), "Flat layouts below require monomorphic elements"); + InlineKlass* vk = InlineKlass::cast(element); + if (is_null_restricted(properties)) { + if (is_non_atomic(properties)) { + // Null-restricted + non-atomic + if (vk->maybe_flat_in_array() && vk->has_non_atomic_layout()) { + return ArrayDescription(FlatArrayKlassKind, properties, LayoutKind::NON_ATOMIC_FLAT); + } else { + return ArrayDescription(RefArrayKlassKind, properties, LayoutKind::REFERENCE); + } + } else { + // Null-restricted + atomic + if (vk->maybe_flat_in_array() && vk->is_naturally_atomic() && vk->has_non_atomic_layout()) { + return ArrayDescription(FlatArrayKlassKind, properties, LayoutKind::NON_ATOMIC_FLAT); + } else if (vk->maybe_flat_in_array() && vk->has_atomic_layout()) { + return ArrayDescription(FlatArrayKlassKind, properties, LayoutKind::ATOMIC_FLAT); + } else { + return ArrayDescription(RefArrayKlassKind, properties, LayoutKind::REFERENCE); + } + } + } else { + // nullable implies atomic, so the non-atomic property is ignored + if (vk->maybe_flat_in_array() && vk->has_nullable_atomic_layout()) { + return ArrayDescription(FlatArrayKlassKind, properties, LayoutKind::NULLABLE_ATOMIC_FLAT); + } else { + return ArrayDescription(RefArrayKlassKind, properties, LayoutKind::REFERENCE); + } + } } 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); + objArrayOop array = RefArrayKlass::cast(this)->allocate(length, CHECK_NULL); objArrayHandle h_array (THREAD, array); if (rank > 1) { if (length != 0) { @@ -188,36 +217,6 @@ oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) { return h_array(); } -// Either oop or narrowOop depending on UseCompressedOops. -void ObjArrayKlass::do_copy(arrayOop s, size_t src_offset, - arrayOop d, size_t dst_offset, int length, TRAPS) { - if (s == d) { - // since source and destination are equal we do not need conversion checks. - assert(length > 0, "sanity check"); - 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::oop_arraycopy(s, src_offset, d, dst_offset, length); - } else { - ArrayAccess::oop_arraycopy(s, src_offset, d, dst_offset, length); - } - } else { - if (null_check) { - ArrayAccess::oop_arraycopy(s, src_offset, d, dst_offset, length); - } else { - ArrayAccess::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"); @@ -227,76 +226,14 @@ void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, 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[]", - type2name_tab[ArrayKlass::cast(d->klass())->element_type()]); - } else { - ss.print("arraycopy: destination type %s is not an array", d->klass()->external_name()); - } - THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); - } - - // Check is all offsets and lengths are non negative - if (src_pos < 0 || dst_pos < 0 || length < 0) { - // Pass specific exception reason. - ResourceMark rm(THREAD); - stringStream ss; - if (src_pos < 0) { - ss.print("arraycopy: source index %d out of bounds for object array[%d]", - src_pos, s->length()); - } else if (dst_pos < 0) { - ss.print("arraycopy: destination index %d out of bounds for object array[%d]", - dst_pos, d->length()); - } else { - ss.print("arraycopy: length %d is negative", length); - } - THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); - } - // Check if the ranges are valid - if ((((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) || - (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length())) { - // Pass specific exception reason. - ResourceMark rm(THREAD); - stringStream ss; - if (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length()) { - ss.print("arraycopy: last source index %u out of bounds for object array[%d]", - (unsigned int) length + (unsigned int) src_pos, s->length()); - } else { - ss.print("arraycopy: last destination index %u out of bounds for object array[%d]", - (unsigned int) length + (unsigned int) dst_pos, d->length()); + if (s->is_flatArray()) { + FlatArrayKlass::cast(s->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD); + return; } - THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } - // Special case. Boundary cases must be checked first - // This allows the following call: copy_array(s, s.length(), d.length(), 0). - // This is correct, since the position is supposed to be an 'in between point', i.e., s.length(), - // points to the right of the last element. - if (length==0) { - return; - } - if (UseCompressedOops) { - size_t src_offset = (size_t) objArrayOopDesc::obj_at_offset(src_pos); - size_t dst_offset = (size_t) objArrayOopDesc::obj_at_offset(dst_pos); - assert(arrayOopDesc::obj_offset_to_raw(s, src_offset, nullptr) == - objArrayOop(s)->obj_at_addr(src_pos), "sanity"); - assert(arrayOopDesc::obj_offset_to_raw(d, dst_offset, nullptr) == - objArrayOop(d)->obj_at_addr(dst_pos), "sanity"); - do_copy(s, src_offset, d, dst_offset, length, CHECK); - } else { - size_t src_offset = (size_t) objArrayOopDesc::obj_at_offset(src_pos); - size_t dst_offset = (size_t) objArrayOopDesc::obj_at_offset(dst_pos); - assert(arrayOopDesc::obj_offset_to_raw(s, src_offset, nullptr) == - objArrayOop(s)->obj_at_addr(src_pos), "sanity"); - assert(arrayOopDesc::obj_offset_to_raw(d, dst_offset, nullptr) == - objArrayOop(d)->obj_at_addr(dst_pos), "sanity"); - do_copy(s, src_offset, d, dst_offset, length, CHECK); - } + assert(s->is_refArray() && d->is_refArray(), "Must be"); + RefArrayKlass::cast(s->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD); } bool ObjArrayKlass::can_be_primary_super_slow() const { @@ -388,38 +325,13 @@ void ObjArrayKlass::print_value_on(outputStream* st) const { #ifndef PRODUCT void ObjArrayKlass::oop_print_on(oop obj, outputStream* st) { - ArrayKlass::oop_print_on(obj, st); - assert(obj->is_objArray(), "must be objArray"); - objArrayOop oa = objArrayOop(obj); - int print_len = MIN2(oa->length(), MaxElementPrintSize); - for(int index = 0; index < print_len; index++) { - st->print(" - %3d : ", index); - if (oa->obj_at(index) != nullptr) { - oa->obj_at(index)->print_value_on(st); - st->cr(); - } else { - st->print_cr("null"); - } - } - int remaining = oa->length() - print_len; - if (remaining > 0) { - st->print_cr(" - <%d more elements, increase MaxElementPrintSize to print>", remaining); - } + ShouldNotReachHere(); } #endif //PRODUCT void ObjArrayKlass::oop_print_value_on(oop obj, outputStream* st) { - assert(obj->is_objArray(), "must be objArray"); - st->print("a "); - element_klass()->print_value_on(st); - int len = objArrayOop(obj)->length(); - st->print("[%d] ", len); - if (obj != nullptr) { - obj->print_address_on(st); - } else { - st->print_cr("null"); - } + ShouldNotReachHere(); } const char* ObjArrayKlass::internal_name() const { diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index 23d0439af10..f656d895213 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -43,14 +43,23 @@ class ObjArrayKlass : public ArrayKlass { // If you add a new field that points to any metaspace object, you // must add this field to ObjArrayKlass::metaspace_pointers_do(). Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass) + protected: + Klass* _element_klass; // The klass of the elements of this array type + protected: // Constructor - ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool null_free); - static ObjArrayKlass* allocate(ClassLoaderData* loader_data, int n, Klass* k, Symbol* name, bool null_free, TRAPS); + ObjArrayKlass(int n, Klass* element_klass, Symbol* name, KlassKind kind, ArrayKlass::ArrayProperties props, markWord mw); + static ObjArrayKlass* allocate(ClassLoaderData* loader_data, int n, Klass* k, Symbol* name, ArrayKlass::ArrayProperties props, TRAPS); public: // For dummy objects ObjArrayKlass() {} + // Compiler/Interpreter offset + static ByteSize element_klass_offset() { return in_ByteSize(offset_of(ObjArrayKlass, _element_klass)); } + + virtual Klass* element_klass() const { return _element_klass; } + virtual void set_element_klass(Klass* k) { _element_klass = k; } + Klass* bottom_klass() const { return _bottom_klass; } void set_bottom_klass(Klass* k) { _bottom_klass = k; } Klass** bottom_klass_addr() { return &_bottom_klass; } @@ -68,9 +77,10 @@ class ObjArrayKlass : public ArrayKlass { // Allocation static ObjArrayKlass* allocate_objArray_klass(ClassLoaderData* loader_data, int n, Klass* element_klass, - bool null_free, TRAPS); + ArrayKlass::ArrayProperties props, TRAPS); - objArrayOop allocate(int length, TRAPS); + static ArrayDescription array_layout_selection(Klass* element, ArrayProperties properties); + // virtual objArrayOop allocate(int length, TRAPS); oop multi_allocate(int rank, jint* sizes, TRAPS); // Copying @@ -81,12 +91,6 @@ class ObjArrayKlass : public ArrayKlass { virtual void metaspace_pointers_do(MetaspaceClosure* iter); - private: - // Either oop or narrowOop depending on UseCompressedOops. - // must be called from within ObjArrayKlass.cpp - void do_copy(arrayOop s, size_t src_offset, - arrayOop d, size_t dst_offset, - int length, TRAPS); public: static ObjArrayKlass* cast(Klass* k) { return const_cast(cast(const_cast(k))); @@ -142,9 +146,9 @@ class ObjArrayKlass : public ArrayKlass { void print_on(outputStream* st) const; void print_value_on(outputStream* st) const; - void oop_print_value_on(oop obj, outputStream* st); + virtual void oop_print_value_on(oop obj, outputStream* st); #ifndef PRODUCT - void oop_print_on (oop obj, outputStream* st); + virtual void oop_print_on (oop obj, outputStream* st); #endif //PRODUCT const char* internal_name() const; diff --git a/src/hotspot/share/oops/objArrayKlass.inline.hpp b/src/hotspot/share/oops/objArrayKlass.inline.hpp index a92c42d21a8..293b951f4c6 100644 --- a/src/hotspot/share/oops/objArrayKlass.inline.hpp +++ b/src/hotspot/share/oops/objArrayKlass.inline.hpp @@ -38,84 +38,42 @@ template void ObjArrayKlass::oop_oop_iterate_elements(objArrayOop a, OopClosureType* closure) { - T* p = (T*)a->base(); - T* const end = p + a->length(); - - for (;p < end; p++) { - Devirtualizer::do_oop(closure, p); - } + ShouldNotReachHere(); } template void ObjArrayKlass::oop_oop_iterate_elements_bounded( objArrayOop a, OopClosureType* closure, void* low, void* high) { + ShouldNotReachHere(); - T* const l = (T*)low; - T* const h = (T*)high; - - T* p = (T*)a->base(); - T* end = p + a->length(); - - if (p < l) { - p = l; - } - if (end > h) { - end = h; - } - - for (;p < end; ++p) { - Devirtualizer::do_oop(closure, p); - } } template void ObjArrayKlass::oop_oop_iterate(oop obj, OopClosureType* closure) { - assert(obj->is_array(), "obj must be array"); - objArrayOop a = objArrayOop(obj); - - if (Devirtualizer::do_metadata(closure)) { - Devirtualizer::do_klass(closure, obj->klass()); - } - - oop_oop_iterate_elements(a, closure); + ShouldNotReachHere(); } template void ObjArrayKlass::oop_oop_iterate_reverse(oop obj, OopClosureType* closure) { - // No reverse implementation ATM. - oop_oop_iterate(obj, closure); + ShouldNotReachHere(); } template void ObjArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) { - assert(obj->is_array(), "obj must be array"); - objArrayOop a = objArrayOop(obj); - - if (Devirtualizer::do_metadata(closure)) { - Devirtualizer::do_klass(closure, a->klass()); - } - - oop_oop_iterate_elements_bounded(a, closure, mr.start(), mr.end()); + ShouldNotReachHere(); } // Like oop_oop_iterate but only iterates over a specified range and only used // for objArrayOops. template void ObjArrayKlass::oop_oop_iterate_range(objArrayOop a, OopClosureType* closure, int start, int end) { - T* low = (T*)a->base() + start; - T* high = (T*)a->base() + end; - - oop_oop_iterate_elements_bounded(a, closure, low, high); + ShouldNotReachHere(); } // Placed here to resolve include cycle between objArrayKlass.inline.hpp and objArrayOop.inline.hpp template void objArrayOopDesc::oop_iterate_range(OopClosureType* blk, int start, int end) { - if (UseCompressedOops) { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } else { - ((ObjArrayKlass*)klass())->oop_oop_iterate_range(this, blk, start, end); - } + ShouldNotReachHere(); } #endif // SHARE_OOPS_OBJARRAYKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/objArrayOop.cpp b/src/hotspot/share/oops/objArrayOop.cpp index 363f6710da8..cb42bc1a784 100644 --- a/src/hotspot/share/oops/objArrayOop.cpp +++ b/src/hotspot/share/oops/objArrayOop.cpp @@ -27,16 +27,6 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -oop objArrayOopDesc::replace_if_null(int index, oop exchange_value) { - ptrdiff_t offs; - if (UseCompressedOops) { - offs = objArrayOopDesc::obj_at_offset(index); - } else { - offs = objArrayOopDesc::obj_at_offset(index); - } - return HeapAccess::oop_atomic_cmpxchg_at(as_oop(), offs, (oop)nullptr, exchange_value); -} - Klass* objArrayOopDesc::element_klass() { return ObjArrayKlass::cast(klass())->element_klass(); } diff --git a/src/hotspot/share/oops/objArrayOop.hpp b/src/hotspot/share/oops/objArrayOop.hpp index 20e2953fee9..f007aa88e6a 100644 --- a/src/hotspot/share/oops/objArrayOop.hpp +++ b/src/hotspot/share/oops/objArrayOop.hpp @@ -62,22 +62,10 @@ class objArrayOopDesc : public arrayOopDesc { // Accessing oop obj_at(int index) const; + oop obj_at(int index, TRAPS) const; void obj_at_put(int index, oop value); - - oop replace_if_null(int index, oop exchange_value); - - // Sizing - size_t object_size() { return object_size(length()); } - - static size_t object_size(int length) { - // This returns the object size in HeapWords. - size_t asz = (size_t)length * heapOopSize; - size_t size_words = heap_word_size(base_offset_in_bytes() + asz); - size_t osz = align_object_size(size_words); - assert(osz < max_jint, "no overflow"); - return osz; - } + void obj_at_put(int index, oop value, TRAPS); Klass* element_klass(); diff --git a/src/hotspot/share/oops/objArrayOop.inline.hpp b/src/hotspot/share/oops/objArrayOop.inline.hpp index 21f95b756de..fdb5baf2ea0 100644 --- a/src/hotspot/share/oops/objArrayOop.inline.hpp +++ b/src/hotspot/share/oops/objArrayOop.inline.hpp @@ -29,7 +29,9 @@ #include "oops/access.hpp" #include "oops/arrayOop.hpp" +#include "oops/flatArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/refArrayKlass.inline.hpp" #include "runtime/globals.hpp" inline HeapWord* objArrayOopDesc::base() const { return (HeapWord*) arrayOopDesc::base(T_OBJECT); } @@ -41,14 +43,38 @@ template T* objArrayOopDesc::obj_at_addr(int index) const { inline oop objArrayOopDesc::obj_at(int index) const { assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); - ptrdiff_t offset = UseCompressedOops ? obj_at_offset(index) : obj_at_offset(index); - return HeapAccess::oop_load_at(as_oop(), offset); + if (is_flatArray()) { + return ((const flatArrayOopDesc* )this)->obj_at(index); + } else { + return ((const refArrayOopDesc* )this)->obj_at(index); + } +} + +inline oop objArrayOopDesc::obj_at(int index, TRAPS) const { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + if (is_flatArray()) { + return ((const flatArrayOopDesc* )this)->obj_at(index, CHECK_NULL); + } else { + return ((const refArrayOopDesc* )this)->obj_at(index, CHECK_NULL); + } } inline void objArrayOopDesc::obj_at_put(int index, oop value) { assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); - ptrdiff_t offset = UseCompressedOops ? obj_at_offset(index) : obj_at_offset(index); - HeapAccess::oop_store_at(as_oop(), offset, value); + if (is_flatArray()) { + ((flatArrayOopDesc* )this)->obj_at_put(index, value); + } else { + ((refArrayOopDesc* )this)->obj_at_put(index, value); + } +} + +inline void objArrayOopDesc::obj_at_put(int index, oop value, TRAPS) { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + if (is_flatArray()) { + ((flatArrayOopDesc* )this)->obj_at_put(index, value, CHECK); + } else { + ((refArrayOopDesc* )this)->obj_at_put(index, value, CHECK); + } } #endif // SHARE_OOPS_OBJARRAYOOP_INLINE_HPP diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 707c824afbc..185e72c165f 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -149,6 +149,7 @@ bool oopDesc::is_instanceRef_noinline() const { return is_instanceRef(); bool oopDesc::is_stackChunk_noinline() const { return is_stackChunk(); } bool oopDesc::is_array_noinline() const { return is_array(); } bool oopDesc::is_objArray_noinline() const { return is_objArray(); } +bool oopDesc::is_refArray_noinline() const { return is_refArray(); } bool oopDesc::is_typeArray_noinline() const { return is_typeArray(); } bool oopDesc::is_flatArray_noinline() const { return is_flatArray(); } bool oopDesc::is_null_free_array_noinline() const { return is_null_free_array(); } diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 5701436a2ee..1c3f3520bf2 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -134,6 +134,7 @@ class oopDesc { inline bool is_objArray() const; inline bool is_typeArray() const; inline bool is_flatArray() const; + inline bool is_refArray() const; inline bool is_null_free_array() const; // type test operations that don't require inclusion of oop.inline.hpp. @@ -142,6 +143,7 @@ class oopDesc { bool is_stackChunk_noinline() const; bool is_array_noinline() const; bool is_objArray_noinline() const; + bool is_refArray_noinline() const; bool is_typeArray_noinline() const; bool is_flatArray_noinline() const; bool is_null_free_array_noinline() const; diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index ccb66d6382a..62475bdcd8b 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -230,6 +230,7 @@ bool oopDesc::is_instanceRef() const { return klass()->is_reference_instance_kla bool oopDesc::is_stackChunk() const { return klass()->is_stack_chunk_instance_klass(); } bool oopDesc::is_array() const { return klass()->is_array_klass(); } bool oopDesc::is_objArray() const { return klass()->is_objArray_klass(); } +bool oopDesc::is_refArray() const { return klass()->is_refArray_klass(); } bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); } bool oopDesc::is_inline_type() const { return mark().is_inline_type(); } diff --git a/src/hotspot/share/oops/oopsHierarchy.hpp b/src/hotspot/share/oops/oopsHierarchy.hpp index 2e1f13bfa95..ded8583c1ae 100644 --- a/src/hotspot/share/oops/oopsHierarchy.hpp +++ b/src/hotspot/share/oops/oopsHierarchy.hpp @@ -48,6 +48,7 @@ typedef class arrayOopDesc* arrayOop; typedef class objArrayOopDesc* objArrayOop; typedef class typeArrayOopDesc* typeArrayOop; typedef class flatArrayOopDesc* flatArrayOop; +typedef class refArrayOopDesc* refArrayOop; #else @@ -157,6 +158,7 @@ DEF_OOP(array); DEF_OOP(objArray); DEF_OOP(typeArray); DEF_OOP(flatArray); +DEF_OOP(refArray); #endif // CHECK_UNHANDLED_OOPS diff --git a/src/hotspot/share/oops/refArrayKlass.cpp b/src/hotspot/share/oops/refArrayKlass.cpp new file mode 100644 index 00000000000..9eb53e38adf --- /dev/null +++ b/src/hotspot/share/oops/refArrayKlass.cpp @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/vmClasses.hpp" +#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/markWord.hpp" +#include "oops/oop.inline.hpp" +#include "oops/refArrayKlass.inline.hpp" +#include "oops/refArrayOop.inline.hpp" +#include "oops/symbol.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/mutexLocker.hpp" +#include "utilities/macros.hpp" + +RefArrayKlass *RefArrayKlass::allocate(ClassLoaderData *loader_data, int n, + Klass *k, Symbol *name, ArrayKlass::ArrayProperties props, + TRAPS) { + assert(RefArrayKlass::header_size() <= InstanceKlass::header_size(), + "array klasses must be same size as InstanceKlass"); + + int size = ArrayKlass::static_size(RefArrayKlass::header_size()); + + return new (loader_data, size, THREAD) RefArrayKlass(n, k, name, props); +} + +RefArrayKlass* RefArrayKlass::allocate_refArray_klass(ClassLoaderData *loader_data, int n, + Klass *element_klass, ArrayKlass::ArrayProperties props, + TRAPS) { + assert(!ArrayKlass::is_null_restricted(props) || (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. + // TODO FIXME: 5 lines below are obsolete but keep arrays working for now, to be removed once array meta-data hierarchy has been fixed + if (ArrayKlass::is_null_restricted(props)) { + super_klass = element_klass->array_klass(CHECK_NULL); + } else { + super_klass = element_super->array_klass(CHECK_NULL); + } + const Array *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); + } + // Fall through because inheritance is acyclic and we hold the global + // recursive lock to allocate all the arrays. + } 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, CHECK_NULL); + + // Initialize instance variables + RefArrayKlass *oak = RefArrayKlass::allocate(loader_data, n, element_klass, + name, props, 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. + ArrayKlass::complete_create_array_klass(oak, super_klass, module, CHECK_NULL); + + // Add all classes to our internal class loader list here, + // including classes in the bootstrap (null) class loader. + // Do this step after creating the mirror so that if the + // mirror creation fails, loaded_classes_do() doesn't find + // an array class without a mirror. + loader_data->add_class(oak); + + return oak; +} + +RefArrayKlass::RefArrayKlass(int n, Klass *element_klass, Symbol *name, + ArrayKlass::ArrayProperties props) + : ObjArrayKlass(n, element_klass, name, Kind, props, + ArrayKlass::is_null_restricted(props) ? markWord::null_free_array_prototype() : markWord::prototype()) { + set_dimension(n); + set_element_klass(element_klass); + + Klass *bk; + if (element_klass->is_refArray_klass()) { + bk = RefArrayKlass::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()); + + if (element_klass->is_array_klass()) { + set_lower_dimension(ArrayKlass::cast(element_klass)); + } + + int lh = array_layout_helper(T_OBJECT); + if (ArrayKlass::is_null_restricted(props)) { + assert(n == 1, "Bytecode does not support null-free multi-dim"); + lh = layout_helper_set_null_free(lh); +#ifdef _LP64 + assert(prototype_header().is_null_free_array(), "sanity"); +#endif + } + set_layout_helper(lh); + assert(is_array_klass(), "sanity"); + assert(is_refArray_klass(), "sanity"); +} + +size_t RefArrayKlass::oop_size(oop obj) const { + // In this assert, we cannot safely access the Klass* with compact headers, + // because size_given_klass() calls oop_size() on objects that might be + // concurrently forwarded, which would overwrite the Klass*. + assert(UseCompactObjectHeaders || obj->is_refArray(), "must be a reference array"); + return refArrayOop(obj)->object_size(); +} + +objArrayOop RefArrayKlass::allocate(int length, TRAPS) { + check_array_allocation_length( + length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL); + size_t size = refArrayOopDesc::object_size(length); + objArrayOop array = (objArrayOop)Universe::heap()->array_allocate( + this, size, length, + /* do_zero */ true, CHECK_NULL); + objArrayHandle array_h(THREAD, array); + return array_h(); +} + +oop RefArrayKlass::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_NULL(vmSymbols::java_lang_NegativeArraySizeException(), + err_msg("%d", *sizes)); + } + } + } + } + return h_array(); +} + +// Either oop or narrowOop depending on UseCompressedOops. +void RefArrayKlass::do_copy(arrayOop s, size_t src_offset, arrayOop d, + size_t dst_offset, int length, TRAPS) { + if (s == d) { + // since source and destination are equal we do not need conversion checks. + assert(length > 0, "sanity check"); + 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 = RefArrayKlass::cast(d->klass())->element_klass(); + Klass *stype = RefArrayKlass::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::oop_arraycopy( + s, src_offset, d, dst_offset, length); + } else { + ArrayAccess::oop_arraycopy(s, src_offset, d, + dst_offset, length); + } + } else { + if (null_check) { + ArrayAccess::oop_arraycopy(s, src_offset, d, + dst_offset, length); + } else { + ArrayAccess::oop_arraycopy( + s, src_offset, d, dst_offset, length); + } + } + } +} + +void RefArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, + int length, TRAPS) { + assert(s->is_refArray(), "must be a reference array"); + + if (UseArrayFlattening) { + if (d->is_flatArray()) { + FlatArrayKlass::cast(d->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD); + return; + } + if (s->is_flatArray()) { + FlatArrayKlass::cast(s->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD); + return; + } + } + + if (!d->is_refArray()) { + ResourceMark rm(THREAD); + stringStream ss; + if (d->is_typeArray()) { + ss.print( + "arraycopy: type mismatch: can not copy object array[] into %s[]", + type2name_tab[ArrayKlass::cast(d->klass())->element_type()]); + } else { + ss.print("arraycopy: destination type %s is not an array", + d->klass()->external_name()); + } + THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); + } + + // Check is all offsets and lengths are non negative + if (src_pos < 0 || dst_pos < 0 || length < 0) { + // Pass specific exception reason. + ResourceMark rm(THREAD); + stringStream ss; + if (src_pos < 0) { + ss.print("arraycopy: source index %d out of bounds for object array[%d]", + src_pos, s->length()); + } else if (dst_pos < 0) { + ss.print( + "arraycopy: destination index %d out of bounds for object array[%d]", + dst_pos, d->length()); + } else { + ss.print("arraycopy: length %d is negative", length); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), + ss.as_string()); + } + // Check if the ranges are valid + if ((((unsigned int)length + (unsigned int)src_pos) > + (unsigned int)s->length()) || + (((unsigned int)length + (unsigned int)dst_pos) > + (unsigned int)d->length())) { + // Pass specific exception reason. + ResourceMark rm(THREAD); + stringStream ss; + if (((unsigned int)length + (unsigned int)src_pos) > + (unsigned int)s->length()) { + ss.print( + "arraycopy: last source index %u out of bounds for object array[%d]", + (unsigned int)length + (unsigned int)src_pos, s->length()); + } else { + ss.print("arraycopy: last destination index %u out of bounds for object " + "array[%d]", + (unsigned int)length + (unsigned int)dst_pos, d->length()); + } + THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), + ss.as_string()); + } + + // Special case. Boundary cases must be checked first + // This allows the following call: copy_array(s, s.length(), d.length(), 0). + // This is correct, since the position is supposed to be an 'in between + // point', i.e., s.length(), points to the right of the last element. + if (length == 0) { + return; + } + if (UseCompressedOops) { + size_t src_offset = + (size_t)refArrayOopDesc::obj_at_offset(src_pos); + size_t dst_offset = + (size_t)refArrayOopDesc::obj_at_offset(dst_pos); + assert(arrayOopDesc::obj_offset_to_raw(s, src_offset, nullptr) == + refArrayOop(s)->obj_at_addr(src_pos), + "sanity"); + assert(arrayOopDesc::obj_offset_to_raw(d, dst_offset, nullptr) == + refArrayOop(d)->obj_at_addr(dst_pos), + "sanity"); + do_copy(s, src_offset, d, dst_offset, length, CHECK); + } else { + size_t src_offset = (size_t)refArrayOopDesc::obj_at_offset(src_pos); + size_t dst_offset = (size_t)refArrayOopDesc::obj_at_offset(dst_pos); + assert(arrayOopDesc::obj_offset_to_raw(s, src_offset, nullptr) == + refArrayOop(s)->obj_at_addr(src_pos), + "sanity"); + assert(arrayOopDesc::obj_offset_to_raw(d, dst_offset, nullptr) == + refArrayOop(d)->obj_at_addr(dst_pos), + "sanity"); + do_copy(s, src_offset, d, dst_offset, length, CHECK); + } +} + +void RefArrayKlass::initialize(TRAPS) { + bottom_klass()->initialize( + THREAD); // dispatches to either InstanceKlass or TypeArrayKlass +} + +void RefArrayKlass::metaspace_pointers_do(MetaspaceClosure *it) { + ObjArrayKlass::metaspace_pointers_do(it); +} + +// Printing + +void RefArrayKlass::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 RefArrayKlass::print_value_on(outputStream *st) const { + assert(is_klass(), "must be klass"); + + element_klass()->print_value_on(st); + st->print("[]"); +} + +#ifndef PRODUCT + +void RefArrayKlass::oop_print_on(oop obj, outputStream *st) { + ArrayKlass::oop_print_on(obj, st); + assert(obj->is_refArray(), "must be refArray"); + refArrayOop oa = refArrayOop(obj); + int print_len = MIN2(oa->length(), MaxElementPrintSize); + for (int index = 0; index < print_len; index++) { + st->print(" - %3d : ", index); + if (oa->obj_at(index) != nullptr) { + oa->obj_at(index)->print_value_on(st); + st->cr(); + } else { + st->print_cr("null"); + } + } + int remaining = oa->length() - print_len; + if (remaining > 0) { + st->print_cr(" - <%d more elements, increase MaxElementPrintSize to print>", + remaining); + } +} + +#endif // PRODUCT + +void RefArrayKlass::oop_print_value_on(oop obj, outputStream *st) { + assert(obj->is_refArray(), "must be refArray"); + st->print("a "); + element_klass()->print_value_on(st); + int len = refArrayOop(obj)->length(); + st->print("[%d] ", len); + if (obj != nullptr) { + obj->print_address_on(st); + } else { + st->print_cr("null"); + } +} + +// Verification + +void RefArrayKlass::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 RefArrayKlass::oop_verify_on(oop obj, outputStream *st) { + ArrayKlass::oop_verify_on(obj, st); + guarantee(obj->is_refArray(), "must be refArray"); + guarantee(obj->is_null_free_array() || (!is_null_free_array_klass()), + "null-free klass but not object"); + refArrayOop oa = refArrayOop(obj); + for (int index = 0; index < oa->length(); index++) { + guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop"); + } +} diff --git a/src/hotspot/share/oops/refArrayKlass.hpp b/src/hotspot/share/oops/refArrayKlass.hpp new file mode 100644 index 00000000000..0c607c0fc87 --- /dev/null +++ b/src/hotspot/share/oops/refArrayKlass.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OOPS_REFARRAYKLASS_HPP +#define SHARE_OOPS_REFARRAYKLASS_HPP + +#include "oops/arrayKlass.hpp" +#include "oops/objArrayKlass.hpp" +#include "utilities/macros.hpp" + +class ClassLoaderData; + +// RefArrayKlass is the klass for arrays of references + +class RefArrayKlass : public ObjArrayKlass { + friend class VMStructs; + friend class JVMCIVMStructs; + + public: + static const KlassKind Kind = RefArrayKlassKind; + + private: + // Constructor + RefArrayKlass(int n, Klass *element_klass, Symbol *name, ArrayKlass::ArrayProperties props); + static RefArrayKlass* allocate(ClassLoaderData *loader_data, int n, Klass *k, Symbol *name, ArrayKlass::ArrayProperties props, TRAPS); + + public: + // For dummy objects + RefArrayKlass() {} + + // Dispatched operation + DEBUG_ONLY(bool is_refArray_klass_slow() const { return true; }) + size_t oop_size(oop obj) const; // TODO FIXME make it virtual in objArrayKlass + + // Allocation + static RefArrayKlass *allocate_refArray_klass(ClassLoaderData *loader_data, + int n, Klass *element_klass, + ArrayKlass::ArrayProperties props, TRAPS); + + objArrayOop allocate(int length, TRAPS); + oop multi_allocate(int rank, jint *sizes, TRAPS); + + // Copying TODO FIXME make copying method in objArrayKlass virtual and default implementation invalid (ShouldNotReachHere()) + void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); + + virtual void metaspace_pointers_do(MetaspaceClosure *iter); + + private: + // Either oop or narrowOop depending on UseCompressedOops. + // must be called from within ObjArrayKlass.cpp + void do_copy(arrayOop s, size_t src_offset, + arrayOop d, size_t dst_offset, + int length, TRAPS); + + public: + static RefArrayKlass *cast(Klass *k) { + return const_cast(cast(const_cast(k))); + } + + static const RefArrayKlass *cast(const Klass *k) { + assert(k->is_refArray_klass(), "cast to RefArrayKlass"); + return static_cast(k); + } + + // Sizing + static int header_size() { return sizeof(RefArrayKlass) / wordSize; } + int size() const { return ArrayKlass::static_size(header_size()); } + + // Initialization (virtual from Klass) + void initialize(TRAPS); + + // Oop fields (and metadata) iterators + // + // The RefArrayKlass iterators also visits the Object's klass. + + // Iterate over oop elements and metadata. + template + inline void oop_oop_iterate(oop obj, OopClosureType *closure); + + // Iterate over oop elements and metadata. + template + inline void oop_oop_iterate_reverse(oop obj, OopClosureType *closure); + + // Iterate over oop elements within mr, and metadata. + template + inline void oop_oop_iterate_bounded(oop obj, OopClosureType *closure, MemRegion mr); + + // Iterate over oop elements within [start, end), and metadata. + template + inline void oop_oop_iterate_range(refArrayOop a, OopClosureType *closure, int start, int end); + + public: + // Iterate over all oop elements. + template + inline void oop_oop_iterate_elements(refArrayOop a, OopClosureType *closure); + + private: + // Iterate over all oop elements with indices within mr. + template + inline void oop_oop_iterate_elements_bounded(refArrayOop a, OopClosureType *closure, void *low, void *high); + + public: + // Printing + void print_on(outputStream *st) const; + void print_value_on(outputStream *st) const; + + void oop_print_value_on(oop obj, outputStream *st); +#ifndef PRODUCT + void oop_print_on(oop obj, outputStream *st); +#endif // PRODUCT + + // Verification + void verify_on(outputStream *st); + + void oop_verify_on(oop obj, outputStream *st); +}; + +#endif // SHARE_OOPS_REFARRAYKLASS_HPP \ No newline at end of file diff --git a/src/hotspot/share/oops/refArrayKlass.inline.hpp b/src/hotspot/share/oops/refArrayKlass.inline.hpp new file mode 100644 index 00000000000..88d9f672bb8 --- /dev/null +++ b/src/hotspot/share/oops/refArrayKlass.inline.hpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OOPS_REFARRAYKLASS_INLINE_HPP +#define SHARE_OOPS_REFARRAYKLASS_INLINE_HPP + +#include "oops/refArrayKlass.hpp" + +#include "memory/memRegion.hpp" +#include "oops/arrayKlass.hpp" +#include "oops/arrayOop.hpp" +#include "oops/klass.hpp" +#include "oops/refArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/devirtualizer.inline.hpp" +#include "utilities/macros.hpp" + +template +void RefArrayKlass::oop_oop_iterate_elements(refArrayOop a, + OopClosureType *closure) { + T *p = (T *)a->base(); + T *const end = p + a->length(); + + for (; p < end; p++) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void RefArrayKlass::oop_oop_iterate_elements_bounded(refArrayOop a, + OopClosureType *closure, + void *low, void *high) { + + T *const l = (T *)low; + T *const h = (T *)high; + + T *p = (T *)a->base(); + T *end = p + a->length(); + + if (p < l) { + p = l; + } + if (end > h) { + end = h; + } + + for (; p < end; ++p) { + Devirtualizer::do_oop(closure, p); + } +} + +template +void RefArrayKlass::oop_oop_iterate(oop obj, OopClosureType *closure) { + assert(obj->is_array(), "obj must be array"); + refArrayOop a = refArrayOop(obj); + + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, obj->klass()); + } + + oop_oop_iterate_elements(a, closure); +} + +template +void RefArrayKlass::oop_oop_iterate_reverse(oop obj, OopClosureType *closure) { + // No reverse implementation ATM. + oop_oop_iterate(obj, closure); +} + +template +void RefArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType *closure, + MemRegion mr) { + assert(obj->is_array(), "obj must be array"); + refArrayOop a = refArrayOop(obj); + + if (Devirtualizer::do_metadata(closure)) { + Devirtualizer::do_klass(closure, a->klass()); + } + + oop_oop_iterate_elements_bounded(a, closure, mr.start(), mr.end()); +} + +// Like oop_oop_iterate but only iterates over a specified range and only used +// for objArrayOops. +template +void RefArrayKlass::oop_oop_iterate_range(refArrayOop a, + OopClosureType *closure, int start, + int end) { + T *low = (T *)a->base() + start; + T *high = (T *)a->base() + end; + + oop_oop_iterate_elements_bounded(a, closure, low, high); +} + +// Placed here to resolve include cycle between objArrayKlass.inline.hpp and +// objArrayOop.inline.hpp +template +void refArrayOopDesc::oop_iterate_range(OopClosureType *blk, int start, + int end) { + if (UseCompressedOops) { + ((RefArrayKlass *)klass()) + ->oop_oop_iterate_range(this, blk, start, end); + } else { + ((RefArrayKlass *)klass()) + ->oop_oop_iterate_range(this, blk, start, end); + } +} + +#endif // SHARE_OOPS_REFARRAYKLASS_INLINE_HPP diff --git a/src/hotspot/share/oops/refArrayOop.cpp b/src/hotspot/share/oops/refArrayOop.cpp new file mode 100644 index 00000000000..1935f582b59 --- /dev/null +++ b/src/hotspot/share/oops/refArrayOop.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "oops/access.inline.hpp" +#include "oops/refArrayKlass.hpp" +#include "oops/refArrayOop.inline.hpp" +#include "oops/oop.inline.hpp" + +oop refArrayOopDesc::replace_if_null(int index, oop exchange_value) { + ptrdiff_t offs; + if (UseCompressedOops) { + offs = refArrayOopDesc::obj_at_offset(index); + } else { + offs = refArrayOopDesc::obj_at_offset(index); + } + return HeapAccess::oop_atomic_cmpxchg_at(as_oop(), offs, (oop)nullptr, exchange_value); +} + +Klass* refArrayOopDesc::element_klass() { + return RefArrayKlass::cast(klass())->element_klass(); +} diff --git a/src/hotspot/share/oops/refArrayOop.hpp b/src/hotspot/share/oops/refArrayOop.hpp new file mode 100644 index 00000000000..15a4018a04a --- /dev/null +++ b/src/hotspot/share/oops/refArrayOop.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OOPS_REFARRAYOOP_HPP +#define SHARE_OOPS_REFARRAYOOP_HPP + +#include "oops/arrayOop.hpp" +#include "utilities/align.hpp" +#include + +class Klass; + +// An refArrayOop is an array containing references (oops). +// Evaluating "String arg[10]" will create an refArrayOop. + +class refArrayOopDesc : public arrayOopDesc { + friend class ArchiveHeapWriter; + friend class RefArrayKlass; + friend class Runtime1; + friend class psPromotionManager; + friend class CSetMarkWordClosure; + friend class Continuation; + template + friend class RawOopWriter; + + template T* obj_at_addr(int index) const; + + template + static ptrdiff_t obj_at_offset(int index) { + return base_offset_in_bytes() + sizeof(T) * index; + } + + public: + // Returns the offset of the first element. + static int base_offset_in_bytes() { + return arrayOopDesc::base_offset_in_bytes(T_OBJECT); + } + + inline static refArrayOop cast(oop o); + + // base is the address following the header. + inline HeapWord* base() const; + + // Accessing + oop obj_at(int index) const; + oop obj_at(int index, TRAPS) const; + + void obj_at_put(int index, oop value); + void obj_at_put(int index, oop value, TRAPS); + + oop replace_if_null(int index, oop exchange_value); + + // Sizing + size_t object_size() { return object_size(length()); } + + static size_t object_size(int length) { + // This returns the object size in HeapWords. + size_t asz = (size_t)length * heapOopSize; + size_t size_words = heap_word_size(base_offset_in_bytes() + asz); + size_t osz = align_object_size(size_words); + assert(osz < max_jint, "no overflow"); + return osz; + } + + Klass* element_klass(); + +public: + // special iterators for index ranges, returns size of object + template + void oop_iterate_range(OopClosureType* blk, int start, int end); +}; + +// See similar requirement for oopDesc. +static_assert(std::is_trivially_default_constructible::value, "required"); + +#endif // SHARE_OOPS_REFARRAYOOP_HPP diff --git a/src/hotspot/share/oops/refArrayOop.inline.hpp b/src/hotspot/share/oops/refArrayOop.inline.hpp new file mode 100644 index 00000000000..f513edc0a2c --- /dev/null +++ b/src/hotspot/share/oops/refArrayOop.inline.hpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025, and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_OOPS_REFARRAYOOP_INLINE_HPP +#define SHARE_OOPS_REFARRAYOOP_INLINE_HPP + +#include "oops/refArrayOop.hpp" + +#include "oops/access.hpp" +#include "oops/arrayOop.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/globals.hpp" + +inline HeapWord *refArrayOopDesc::base() const { + return (HeapWord *)arrayOopDesc::base(T_OBJECT); +} + +inline refArrayOop refArrayOopDesc::cast(oop o) { + assert(o->is_refArray(), "Must be a refArray"); + return (refArrayOop)o; +} + +template T *refArrayOopDesc::obj_at_addr(int index) const { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + return &((T *)base())[index]; +} + +inline oop refArrayOopDesc::obj_at(int index) const { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + ptrdiff_t offset = UseCompressedOops ? obj_at_offset(index) + : obj_at_offset(index); + return HeapAccess::oop_load_at(as_oop(), offset); +} + +inline oop refArrayOopDesc::obj_at(int index, TRAPS) const { + return obj_at(index); +} + +inline void refArrayOopDesc::obj_at_put(int index, oop value) { + assert(is_within_bounds(index), "index %d out of bounds %d", index, length()); + assert(!is_null_free_array() || value != nullptr, "Trying to write null to a null free array"); + ptrdiff_t offset = UseCompressedOops ? obj_at_offset(index) + : obj_at_offset(index); + HeapAccess::oop_store_at(as_oop(), offset, value); +} + +inline void refArrayOopDesc::obj_at_put(int index, oop value, TRAPS) { + if (is_null_free_array() && value == nullptr) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Cannot store null in a null-restricted array"); + } + obj_at_put(index, value); +} + +#endif // SHARE_OOPS_REFARRAYOOP_INLINE_HPP diff --git a/src/hotspot/share/oops/typeArrayKlass.cpp b/src/hotspot/share/oops/typeArrayKlass.cpp index 1ae43d00004..80a30f44b24 100644 --- a/src/hotspot/share/oops/typeArrayKlass.cpp +++ b/src/hotspot/share/oops/typeArrayKlass.cpp @@ -81,7 +81,7 @@ u2 TypeArrayKlass::compute_modifier_flags() const { | identity_flag; } -TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, Kind) { +TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, Kind, ArrayKlass::ArrayProperties::DEFAULT) { set_layout_helper(array_layout_helper(type)); assert(is_array_klass(), "sanity"); assert(is_typeArray_klass(), "sanity"); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index d057372f3eb..9b35b6438b8 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2327,7 +2327,7 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ const TypeOopPtr* result = nullptr; // See if it is a narrow oop array. if (adr_type->isa_aryptr()) { - if (adr_type->offset() >= objArrayOopDesc::base_offset_in_bytes()) { + if (adr_type->offset() >= refArrayOopDesc::base_offset_in_bytes()) { const TypeOopPtr* elem_type = adr_type->is_aryptr()->elem()->make_oopptr(); null_free = adr_type->is_aryptr()->is_null_free(); if (elem_type != nullptr && elem_type->is_loaded()) { @@ -4541,7 +4541,7 @@ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region, switch(kind) { case ObjectArray: case NonObjectArray: { - value = Klass::_lh_array_tag_obj_value; + value = Klass::_lh_array_tag_ref_value; layout_val = _gvn.transform(new RShiftINode(layout_val, intcon(Klass::_lh_array_tag_shift))); btest = (kind == ObjectArray) ? BoolTest::eq : BoolTest::ne; break; diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp index c53919f35ce..16f0c770537 100644 --- a/src/hotspot/share/opto/parseHelper.cpp +++ b/src/hotspot/share/opto/parseHelper.cpp @@ -248,7 +248,7 @@ Node* Parse::array_store_check(Node*& adr, const Type*& elemtype) { // Come here for polymorphic array klasses // Extract the array element class - int element_klass_offset = in_bytes(ArrayKlass::element_klass_offset()); + int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p2, tak)); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 5c88e4f23c9..ff7437f918f 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -386,7 +386,21 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, oopDe Handle holder(current, array_type->klass_holder()); // keep the array klass alive FlatArrayKlass* fak = FlatArrayKlass::cast(array_type); InlineKlass* vk = fak->element_klass(); - result = oopFactory::new_flatArray(vk, len, fak->layout_kind(), THREAD); + ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; + switch(fak->layout_kind()) { + case LayoutKind::ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NULL_RESTRICTED; + break; + case LayoutKind::NON_ATOMIC_FLAT: + props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::NULL_RESTRICTED | ArrayKlass::ArrayProperties::NON_ATOMIC); + break; + case LayoutKind::NULLABLE_ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NON_ATOMIC; + break; + default: + ShouldNotReachHere(); + } + result = oopFactory::new_flatArray(vk, len, props, fak->layout_kind(), THREAD); if (array_type->is_null_free_array_klass() && !h_init_val.is_null()) { // Null-free arrays need to be initialized for (int i = 0; i < len; i++) { @@ -400,7 +414,7 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::new_array_C(Klass* array_type, int len, oopDe result = oopFactory::new_typeArray(elem_type, len, THREAD); } else { Handle holder(current, array_type->klass_holder()); // keep the array klass alive - ObjArrayKlass* array_klass = ObjArrayKlass::cast(array_type); + RefArrayKlass* array_klass = RefArrayKlass::cast(array_type); result = array_klass->allocate(len, THREAD); if (array_type->is_null_free_array_klass() && !h_init_val.is_null()) { // Null-free arrays need to be initialized @@ -2418,7 +2432,7 @@ const TypeFunc *OptoRuntime::pack_inline_type_Type() { JRT_BLOCK_ENTRY(void, OptoRuntime::load_unknown_inline_C(flatArrayOopDesc* array, int index, JavaThread* current)) JRT_BLOCK; - oop buffer = array->read_value_from_flat_array(index, THREAD); + oop buffer = array->obj_at(index, THREAD); deoptimize_caller_frame(current, HAS_PENDING_EXCEPTION); current->set_vm_result_oop(buffer); JRT_BLOCK_END; @@ -2443,7 +2457,7 @@ const TypeFunc* OptoRuntime::load_unknown_inline_Type() { JRT_BLOCK_ENTRY(void, OptoRuntime::store_unknown_inline_C(instanceOopDesc* buffer, flatArrayOopDesc* array, int index, JavaThread* current)) JRT_BLOCK; - array->write_value_to_flat_array(buffer, index, THREAD); + array->obj_at_put(index, buffer, THREAD); if (HAS_PENDING_EXCEPTION) { fatal("This entry must be changed to be a non-leaf entry because writing to a flat array can now throw an exception"); } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 05278e7dcde..e9f7859944e 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2352,9 +2352,11 @@ JNI_ENTRY(jobjectArray, jni_NewObjectArray(JNIEnv *env, jsize length, jclass ele jobjectArray ret = nullptr; DT_RETURN_MARK(NewObjectArray, jobjectArray, (const jobjectArray&)ret); Klass* ek = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(elementClass)); - Klass* ak = ek->array_klass(CHECK_NULL); - ObjArrayKlass::cast(ak)->initialize(CHECK_NULL); - objArrayOop result = ObjArrayKlass::cast(ak)->allocate(length, CHECK_NULL); + + // Make sure bottom_klass is initialized. + ek->initialize(CHECK_NULL); + objArrayOop result = oopFactory::new_objArray(ek, length, CHECK_NULL); + oop initial_value = JNIHandles::resolve(initialElement); if (initial_value != nullptr) { // array already initialized with null for (int index = 0; index < length; index++) { @@ -2372,26 +2374,18 @@ JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, js HOTSPOT_JNI_GETOBJECTARRAYELEMENT_ENTRY(env, array, index); jobject ret = nullptr; DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret); - oop res = nullptr; - arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array)); - if (arr->is_within_bounds(index)) { - if (arr->is_flatArray()) { - flatArrayOop a = flatArrayOop(JNIHandles::resolve_non_null(array)); - res = a->read_value_from_flat_array(index, CHECK_NULL); - assert(res != nullptr || !arr->is_null_free_array(), "Invalid value"); - } else { - assert(arr->is_objArray(), "If not a valueArray. must be an objArray"); - objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); - res = a->obj_at(index); - } + objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); + if (a->is_within_bounds(index)) { + oop res = a->obj_at(index, CHECK_NULL); + assert(res != nullptr || !a->is_null_free_array(), "Invalid value"); + ret = JNIHandles::make_local(THREAD, res); + return ret; } else { ResourceMark rm(THREAD); stringStream ss; - ss.print("Index %d out of bounds for length %d", index,arr->length()); + ss.print("Index %d out of bounds for length %d", index, a->length()); THROW_MSG_NULL(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } - ret = JNIHandles::make_local(THREAD, res); - return ret; JNI_END DT_VOID_RETURN_MARK_DECL(SetObjectArrayElement @@ -2401,44 +2395,30 @@ JNI_ENTRY(void, jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value); DT_VOID_RETURN_MARK(SetObjectArrayElement); - bool oob = false; - int length = -1; - oop res = nullptr; - arrayOop arr((arrayOop)JNIHandles::resolve_non_null(array)); - if (arr->is_within_bounds(index)) { - if (arr->is_flatArray()) { - flatArrayOop a = flatArrayOop(JNIHandles::resolve_non_null(array)); - oop v = JNIHandles::resolve(value); - FlatArrayKlass* vaklass = FlatArrayKlass::cast(a->klass()); - InlineKlass* element_vklass = vaklass->element_klass(); - a->write_value_to_flat_array(v, index, CHECK); - } else { - assert(arr->is_objArray(), "If not a valueArray. must be an objArray"); - objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); - oop v = JNIHandles::resolve(value); - if (v == nullptr || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) { - if (v == nullptr && ObjArrayKlass::cast(a->klass())->is_null_free_array_klass()) { - THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Cannot store null in a null-restricted array"); - } - a->obj_at_put(index, v); - } else { - ResourceMark rm(THREAD); - stringStream ss; - Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass(); - ss.print("type mismatch: can not store %s to %s[%d]", - v->klass()->external_name(), - bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(), - index); - for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { - ss.print("[]"); - } - THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); - } - } + objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); + oop v = JNIHandles::resolve(value); + if (a->is_within_bounds(index)) { + // TODO FIXME Temporary hack, to be removed when FlatArrayKlass is made a sub-class of ObjArrayKlass + Klass* ek = a->is_flatArray() ? FlatArrayKlass::cast(a->klass())->element_klass() : RefArrayKlass::cast(a->klass())->element_klass(); + if (v == nullptr || v->is_a(ek)) { + a->obj_at_put(index, v, CHECK); + } else { + ResourceMark rm(THREAD); + stringStream ss; + Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass(); + ss.print("type mismatch: can not store %s to %s[%d]", + v->klass()->external_name(), + bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(), + index); + for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { + ss.print("[]"); + } + THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); + } } else { ResourceMark rm(THREAD); stringStream ss; - ss.print("Index %d out of bounds for length %d", index, arr->length()); + ss.print("Index %d out of bounds for length %d", index, a->length()); THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); } JNI_END diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 85787087a46..4f9ca505ed0 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -66,6 +66,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/refArrayOop.inline.hpp" #include "prims/foreignGlobals.hpp" #include "prims/jvm_misc.hpp" #include "prims/jvmtiExport.hpp" @@ -433,7 +434,7 @@ JVM_ENTRY(jarray, JVM_CopyOfSpecialArray(JNIEnv *env, jarray orig, jint from, ji oop array = nullptr; arrayOop org = (arrayOop)o; arrayHandle oh(THREAD, org); - ArrayKlass* ak = ArrayKlass::cast(org->klass()); + ObjArrayKlass* ak = ObjArrayKlass::cast(org->klass()); InlineKlass* vk = InlineKlass::cast(ak->element_klass()); int len = to - from; // length of the new array if (ak->is_null_free_array_klass()) { @@ -444,7 +445,21 @@ JVM_ENTRY(jarray, JVM_CopyOfSpecialArray(JNIEnv *env, jarray orig, jint from, ji if (org->is_flatArray()) { FlatArrayKlass* fak = FlatArrayKlass::cast(org->klass()); LayoutKind lk = fak->layout_kind(); - array = oopFactory::new_flatArray(vk, len, lk, CHECK_NULL); + ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; + switch(lk) { + case LayoutKind::ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NULL_RESTRICTED; + break; + case LayoutKind::NON_ATOMIC_FLAT: + props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::NULL_RESTRICTED | ArrayKlass::ArrayProperties::NON_ATOMIC); + break; + case LayoutKind::NULLABLE_ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NON_ATOMIC; + break; + default: + ShouldNotReachHere(); + } + array = oopFactory::new_flatArray(vk, len, props, lk, CHECK_NULL); arrayHandle ah(THREAD, (arrayOop)array); int end = to < oh()->length() ? to : oh()->length(); for (int i = from; i < end; i++) { @@ -485,17 +500,10 @@ JVM_ENTRY(jarray, JVM_NewNullRestrictedNonAtomicArray(JNIEnv *env, jclass elmCla } validate_array_arguments(klass, len, CHECK_NULL); InlineKlass* vk = InlineKlass::cast(klass); - oop array = nullptr; - if (vk->maybe_flat_in_array() && vk->has_non_atomic_layout()) { - array = oopFactory::new_flatArray(vk, len, LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); - for (int i = 0; i < len; i++) { - ((flatArrayOop)array)->write_value_to_flat_array(init_h(), i, CHECK_NULL); - } - } else { - array = oopFactory::new_null_free_objArray(vk, len, CHECK_NULL); - for (int i = 0; i < len; i++) { - ((objArrayOop)array)->obj_at_put(i, init_h()); - } + ArrayKlass::ArrayProperties props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::NON_ATOMIC | ArrayKlass::ArrayProperties::NULL_RESTRICTED); + objArrayOop array = oopFactory::new_objArray2(klass, len, props, CHECK_NULL); + for (int i = 0; i < len; i++) { + array->obj_at_put(i, init_h() /*, CHECK_NULL*/ ); } return (jarray) JNIHandles::make_local(THREAD, array); JVM_END @@ -513,24 +521,10 @@ JVM_ENTRY(jarray, JVM_NewNullRestrictedAtomicArray(JNIEnv *env, jclass elmClass, } validate_array_arguments(klass, len, CHECK_NULL); InlineKlass* vk = InlineKlass::cast(klass); - oop array = nullptr; - if (vk->maybe_flat_in_array() && vk->is_naturally_atomic() && vk->has_non_atomic_layout()) { - array = oopFactory::new_flatArray(vk, len, LayoutKind::NON_ATOMIC_FLAT, CHECK_NULL); - for (int i = 0; i < len; i++) { - ((flatArrayOop)array)->write_value_to_flat_array(init_h(), i, CHECK_NULL); - } - } else if (vk->maybe_flat_in_array() && vk->has_atomic_layout()) { - array = oopFactory::new_flatArray(vk, len, LayoutKind::ATOMIC_FLAT, CHECK_NULL); - for (int i = 0; i < len; i++) { - ((flatArrayOop)array)->write_value_to_flat_array(init_h(), i, CHECK_NULL); - } - } else { - array = oopFactory::new_null_free_objArray(vk, len, CHECK_NULL); - for (int i = 0; i < len; i++) { - // need a type check here - - ((objArrayOop)array)->obj_at_put(i, init_h()); - } + ArrayKlass::ArrayProperties props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::NULL_RESTRICTED); + objArrayOop array = oopFactory::new_objArray2(klass, len, props, CHECK_NULL); + for (int i = 0; i < len; i++) { + array->obj_at_put(i, init_h() /*, CHECK_NULL*/ ); } return (jarray) JNIHandles::make_local(THREAD, array); JVM_END @@ -541,12 +535,8 @@ JVM_ENTRY(jarray, JVM_NewNullableAtomicArray(JNIEnv *env, jclass elmClass, jint klass->initialize(CHECK_NULL); validate_array_arguments(klass, len, CHECK_NULL); InlineKlass* vk = InlineKlass::cast(klass); - oop array = nullptr; - if (vk->maybe_flat_in_array() && vk->has_nullable_atomic_layout()) { - array = oopFactory::new_flatArray(vk, len, LayoutKind::NULLABLE_ATOMIC_FLAT, CHECK_NULL); - } else { - array = oopFactory::new_objArray(vk, len, CHECK_NULL); - } + ArrayKlass::ArrayProperties props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::DEFAULT); + objArrayOop array = oopFactory::new_objArray2(klass, len, props, CHECK_NULL); return (jarray) JNIHandles::make_local(THREAD, array); JVM_END @@ -566,7 +556,7 @@ JVM_ENTRY(jboolean, JVM_IsAtomicArray(JNIEnv *env, jobject obj)) // - the array uses an atomic flat layout: NULLABLE_ATOMIC_FLAT or ATOMIC_FLAT // - the array is flat and its component type is naturally atomic arrayOop oop = arrayOop(JNIHandles::resolve_non_null(obj)); - if (oop->is_objArray()) return true; + if (oop->is_refArray()) return true; if (oop->is_flatArray()) { FlatArrayKlass* fak = FlatArrayKlass::cast(oop->klass()); if (fak->layout_kind() == LayoutKind::ATOMIC_FLAT || fak->layout_kind() == LayoutKind::NULLABLE_ATOMIC_FLAT) { @@ -1356,7 +1346,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassInterfaces(JNIEnv *env, jclass cls)) InstanceKlass* ik = InstanceKlass::cast(klass); size = ik->local_interfaces()->length(); } else { - assert(klass->is_objArray_klass() || klass->is_typeArray_klass() || klass->is_flatArray_klass(), "Illegal mirror klass"); + assert(klass->is_refArray_klass() || klass->is_typeArray_klass() || klass->is_flatArray_klass(), "Illegal mirror klass"); size = 2; } @@ -3787,12 +3777,13 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject if (k != vmClasses::Thread_klass()) { THROW_NULL(vmSymbols::java_lang_IllegalArgumentException()); } + refArrayHandle rah(THREAD, (refArrayOop)ah()); // j.l.Thread is an identity class, arrays are always reference arrays ResourceMark rm(THREAD); GrowableArray* thread_handle_array = new GrowableArray(num_threads); for (int i = 0; i < num_threads; i++) { - oop thread_obj = ah->obj_at(i); + oop thread_obj = rah->obj_at(i); instanceHandle h(THREAD, (instanceOop) thread_obj); thread_handle_array->append(h); } diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index a078b7517f5..e7a82d24a53 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -429,7 +429,21 @@ UNSAFE_ENTRY(jarray, Unsafe_NewSpecialArray(JNIEnv *env, jobject unsafe, jclass if (!UseArrayFlattening || !vk->is_layout_supported(lk)) { THROW_MSG_NULL(vmSymbols::java_lang_UnsupportedOperationException(), "Layout not supported"); } - oop array = oopFactory::new_flatArray(vk, len, lk, CHECK_NULL); + ArrayKlass::ArrayProperties props = ArrayKlass::ArrayProperties::DEFAULT; + switch(lk) { + case LayoutKind::ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NULL_RESTRICTED; + break; + case LayoutKind::NON_ATOMIC_FLAT: + props = (ArrayKlass::ArrayProperties)(ArrayKlass::ArrayProperties::NULL_RESTRICTED | ArrayKlass::ArrayProperties::NON_ATOMIC); + break; + case LayoutKind::NULLABLE_ATOMIC_FLAT: + props = ArrayKlass::ArrayProperties::NON_ATOMIC; + break; + default: + ShouldNotReachHere(); + } + oop array = oopFactory::new_flatArray(vk, len, props, lk, CHECK_NULL); return (jarray) JNIHandles::make_local(THREAD, array); } UNSAFE_END @@ -844,7 +858,7 @@ static void getBaseAndScale(int& base, int& scale, jclass clazz, TRAPS) { if (k == nullptr || !k->is_array_klass()) { THROW(vmSymbols::java_lang_InvalidClassException()); - } else if (k->is_objArray_klass()) { + } else if (k->is_refArray_klass()) { base = arrayOopDesc::base_offset_in_bytes(T_OBJECT); scale = heapOopSize; } else if (k->is_typeArray_klass()) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 8f7aa00d7a8..a8badb7c921 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1303,8 +1303,8 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* int len = sv->field_size() / type2size[ak->element_type()]; InternalOOMEMark iom(THREAD); obj = ak->allocate(len, THREAD); - } else if (k->is_objArray_klass()) { - ObjArrayKlass* ak = ObjArrayKlass::cast(k); + } else if (k->is_refArray_klass()) { + RefArrayKlass* ak = RefArrayKlass::cast(k); InternalOOMEMark iom(THREAD); obj = ak->allocate(sv->field_size(), THREAD); } diff --git a/src/hotspot/share/runtime/handles.hpp b/src/hotspot/share/runtime/handles.hpp index cb0ea8cc3b2..c0d2bb1e8b8 100644 --- a/src/hotspot/share/runtime/handles.hpp +++ b/src/hotspot/share/runtime/handles.hpp @@ -130,6 +130,7 @@ DEF_HANDLE(array , is_array_noinline ) DEF_HANDLE(objArray , is_objArray_noinline ) DEF_HANDLE(typeArray , is_typeArray_noinline ) DEF_HANDLE(flatArray , is_flatArray_noinline ) +DEF_HANDLE(refArray , is_refArray_noinline ) //------------------------------------------------------------------------------------------------------------------------ diff --git a/src/hotspot/share/runtime/handles.inline.hpp b/src/hotspot/share/runtime/handles.inline.hpp index f4abe0ba7fd..fd2e4e67c7f 100644 --- a/src/hotspot/share/runtime/handles.inline.hpp +++ b/src/hotspot/share/runtime/handles.inline.hpp @@ -62,6 +62,7 @@ DEF_HANDLE_CONSTR(array , is_array_noinline ) DEF_HANDLE_CONSTR(objArray , is_objArray_noinline ) DEF_HANDLE_CONSTR(typeArray, is_typeArray_noinline) DEF_HANDLE_CONSTR(flatArray, is_flatArray_noinline) +DEF_HANDLE_CONSTR(refArray , is_refArray_noinline ) // Constructor for metadata handles #define DEF_METADATA_HANDLE_FN(name, type) \ diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index c6b733acd6a..2ced5a6b50e 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -230,7 +230,8 @@ BasicType Reflection::array_get(jvalue* value, arrayOop a, int index, TRAPS) { THROW_(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), T_ILLEGAL); } if (a->is_objArray()) { - value->l = cast_from_oop(objArrayOop(a)->obj_at(index)); + oop o = objArrayOop(a)->obj_at(index, CHECK_(T_ILLEGAL)); // reading from a flat array can throw an OOM + value->l = cast_from_oop(o); return T_OBJECT; } else { assert(a->is_typeArray(), "just checking"); @@ -1066,8 +1067,8 @@ static oop invoke(InstanceKlass* klass, } for (int i = 0; i < args_len; i++) { - oop type_mirror = ptypes->obj_at(i); - oop arg = args->obj_at(i); + oop type_mirror = ptypes->obj_at(i, CHECK_NULL); + oop arg = args->obj_at(i, CHECK_NULL); if (java_lang_Class::is_primitive(type_mirror)) { jvalue value; BasicType ptype = basic_type_mirror_to_basic_type(type_mirror); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 019880c5968..a6024e64b80 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -937,9 +937,10 @@ declare_type(Metadata, MetaspaceObj) \ declare_type(Klass, Metadata) \ declare_type(ArrayKlass, Klass) \ - declare_type(FlatArrayKlass, ArrayKlass) \ - declare_type(ObjArrayKlass, ArrayKlass) \ declare_type(TypeArrayKlass, ArrayKlass) \ + declare_type(ObjArrayKlass, ArrayKlass) \ + declare_type(FlatArrayKlass, ArrayKlass) \ + declare_type(RefArrayKlass, ArrayKlass) \ declare_type(InstanceKlass, Klass) \ declare_type(InlineKlass, InstanceKlass) \ declare_type(InstanceClassLoaderKlass, InstanceKlass) \ @@ -1405,6 +1406,7 @@ declare_constant(Klass::_lh_array_tag_shift) \ declare_constant(Klass::_lh_array_tag_type_value) \ declare_constant(Klass::_lh_array_tag_obj_value) \ + declare_constant(Klass::_lh_array_tag_ref_value) \ \ declare_constant(Method::nonvirtual_vtable_index) \ declare_constant(Method::extra_stack_entries_for_jsr292) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java index 50b5d27eab4..983c00b903c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/memory/FileMapInfo.java @@ -116,7 +116,7 @@ private static void initialize(TypeDataBase db) { } private static void populateMetadataTypeArray(TypeDataBase db) { - metadataTypeArray = new Type[11]; + metadataTypeArray = new Type[12]; metadataTypeArray[0] = db.lookupType("ConstantPool"); metadataTypeArray[1] = db.lookupType("InstanceKlass"); @@ -129,6 +129,7 @@ private static void populateMetadataTypeArray(TypeDataBase db) { metadataTypeArray[8] = db.lookupType("TypeArrayKlass"); metadataTypeArray[9] = db.lookupType("FlatArrayKlass"); metadataTypeArray[10] = db.lookupType("InlineKlass"); + metadataTypeArray[11] = db.lookupType("RefArrayKlass"); } public FileMapHeader getHeader() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 1b8a9d0ef69..5c80d84de72 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -50,6 +50,7 @@ public void update(Observable o, Object data) { public static int LH_ARRAY_TAG_SHIFT; public static int LH_ARRAY_TAG_TYPE_VALUE; public static int LH_ARRAY_TAG_OBJ_VALUE; + public static int LH_ARRAY_TAG_REF_VALUE; private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("Klass"); @@ -75,6 +76,7 @@ private static synchronized void initialize(TypeDataBase db) throws WrongTypeExc LH_ARRAY_TAG_SHIFT = db.lookupIntConstant("Klass::_lh_array_tag_shift").intValue(); LH_ARRAY_TAG_TYPE_VALUE = db.lookupIntConstant("Klass::_lh_array_tag_type_value").intValue(); LH_ARRAY_TAG_OBJ_VALUE = db.lookupIntConstant("Klass::_lh_array_tag_obj_value").intValue(); + LH_ARRAY_TAG_REF_VALUE = db.lookupIntConstant("Klass::_lh_array_tag_ref_value").intValue(); } diff --git a/test/hotspot/gtest/oops/test_objArrayOop.cpp b/test/hotspot/gtest/oops/test_objArrayOop.cpp index 22c9b2efc11..112a08f9a53 100644 --- a/test/hotspot/gtest/oops/test_objArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_objArrayOop.cpp @@ -22,9 +22,12 @@ */ #include "oops/objArrayOop.hpp" +#include "oops/refArrayOop.hpp" #include "unittest.hpp" #include "utilities/globalDefinitions.hpp" +// TODO FIXME This test needs to be rewritten after objArray/refArray/flatArray rework + TEST_VM(objArrayOop, osize) { static const struct { int objal; bool ccp; bool coops; bool coh; int result; @@ -57,7 +60,7 @@ TEST_VM(objArrayOop, osize) { for (int i = 0; x[i].result != -1; i++) { if (x[i].objal == (int)ObjectAlignmentInBytes && x[i].ccp == UseCompressedClassPointers && x[i].coops == UseCompressedOops && x[i].coh == UseCompactObjectHeaders) { - EXPECT_EQ(objArrayOopDesc::object_size(1), (size_t)x[i].result); + EXPECT_EQ(refArrayOopDesc::object_size(1), (size_t)x[i].result); } } }