< prev index next >

src/hotspot/share/oops/objArrayKlass.cpp

Print this page
*** 30,10 ***
--- 30,11 ---
  #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"

*** 43,32 ***
  #include "oops/symbol.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/mutexLocker.hpp"
  #include "utilities/macros.hpp"
  
! ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n, Klass* k, Symbol* name, TRAPS) {
    assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(),
        "array klasses must be same size as InstanceKlass");
  
    int size = ArrayKlass::static_size(ObjArrayKlass::header_size());
  
!   return new (loader_data, size, THREAD) ObjArrayKlass(n, k, name);
  }
  
  ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
!                                                       int n, Klass* element_klass, TRAPS) {
  
    // Eagerly allocate the direct array supertype.
    Klass* super_klass = nullptr;
    if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
      assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
      Klass* element_super = element_klass->super();
      if (element_super != nullptr) {
        // The element type has a direct super.  E.g., String[] has direct super of Object[].
        // Also, see if the element has secondary supertypes.
        // We need an array type for each before creating this array type.
!       super_klass = element_super->array_klass(CHECK_NULL);
        const Array<Klass*>* element_supers = element_klass->secondary_supers();
        for (int i = element_supers->length() - 1; i >= 0; i--) {
          Klass* elem_super = element_supers->at(i);
          elem_super->array_klass(CHECK_NULL);
        }
--- 44,40 ---
  #include "oops/symbol.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/mutexLocker.hpp"
  #include "utilities/macros.hpp"
  
! ObjArrayKlass* ObjArrayKlass::allocate(ClassLoaderData* loader_data, int n,
+                                        Klass* k, Symbol* name, bool null_free,
+                                        TRAPS) {
    assert(ObjArrayKlass::header_size() <= InstanceKlass::header_size(),
        "array klasses must be same size as InstanceKlass");
  
    int size = ArrayKlass::static_size(ObjArrayKlass::header_size());
  
!   return new (loader_data, size, THREAD) ObjArrayKlass(n, k, name, null_free);
  }
  
  ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
!                                                       int n, Klass* element_klass,
+                                                       bool null_free, TRAPS) {
+   assert(!null_free || (n == 1 && element_klass->is_inline_klass()), "null-free unsupported");
  
    // Eagerly allocate the direct array supertype.
    Klass* super_klass = nullptr;
    if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
      assert(MultiArray_lock->holds_lock(THREAD), "must hold lock after bootstrapping");
      Klass* element_super = element_klass->super();
      if (element_super != nullptr) {
        // The element type has a direct super.  E.g., String[] has direct super of Object[].
        // Also, see if the element has secondary supertypes.
        // We need an array type for each before creating this array type.
!       if (null_free) {
+         super_klass = element_klass->array_klass(CHECK_NULL);
+       } else {
+         super_klass = element_super->array_klass(CHECK_NULL);
+       }
        const Array<Klass*>* element_supers = element_klass->secondary_supers();
        for (int i = element_supers->length() - 1; i >= 0; i--) {
          Klass* elem_super = element_supers->at(i);
          elem_super->array_klass(CHECK_NULL);
        }

*** 78,32 ***
        super_klass = vmClasses::Object_klass();
      }
    }
  
    // Create type name for klass.
!   Symbol* name = nullptr;
-   {
-     ResourceMark rm(THREAD);
-     char *name_str = element_klass->name()->as_C_string();
-     int len = element_klass->name()->utf8_length();
-     char *new_str = NEW_RESOURCE_ARRAY(char, len + 4);
-     int idx = 0;
-     new_str[idx++] = JVM_SIGNATURE_ARRAY;
-     if (element_klass->is_instance_klass()) { // it could be an array or simple type
-       new_str[idx++] = JVM_SIGNATURE_CLASS;
-     }
-     memcpy(&new_str[idx], name_str, len * sizeof(char));
-     idx += len;
-     if (element_klass->is_instance_klass()) {
-       new_str[idx++] = JVM_SIGNATURE_ENDCLASS;
-     }
-     new_str[idx++] = '\0';
-     name = SymbolTable::new_symbol(new_str);
-   }
  
    // Initialize instance variables
!   ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, CHECK_NULL);
  
    ModuleEntry* module = oak->module();
    assert(module != nullptr, "No module entry for array");
  
    // Call complete_create_array_klass after all instance variables has been initialized.
--- 87,14 ---
        super_klass = vmClasses::Object_klass();
      }
    }
  
    // Create type name for klass.
!   Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, CHECK_NULL);
  
    // Initialize instance variables
!   ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, null_free, CHECK_NULL);
  
    ModuleEntry* module = oak->module();
    assert(module != nullptr, "No module entry for array");
  
    // Call complete_create_array_klass after all instance variables has been initialized.

*** 117,17 ***
    loader_data->add_class(oak);
  
    return oak;
  }
  
! ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, Kind) {
    set_dimension(n);
    set_element_klass(element_klass);
  
    Klass* bk;
    if (element_klass->is_objArray_klass()) {
      bk = ObjArrayKlass::cast(element_klass)->bottom_klass();
    } else {
      bk = element_klass;
    }
    assert(bk != nullptr && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
    set_bottom_klass(bk);
--- 108,19 ---
    loader_data->add_class(oak);
  
    return oak;
  }
  
! ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool null_free) : ArrayKlass(name, Kind) {
    set_dimension(n);
    set_element_klass(element_klass);
  
    Klass* bk;
    if (element_klass->is_objArray_klass()) {
      bk = ObjArrayKlass::cast(element_klass)->bottom_klass();
+   } else if (element_klass->is_flatArray_klass()) {
+     bk = FlatArrayKlass::cast(element_klass)->element_klass();
    } else {
      bk = element_klass;
    }
    assert(bk != nullptr && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
    set_bottom_klass(bk);

*** 135,11 ***
  
    if (element_klass->is_array_klass()) {
      set_lower_dimension(ArrayKlass::cast(element_klass));
    }
  
!   set_layout_helper(array_layout_helper(T_OBJECT));
    assert(is_array_klass(), "sanity");
    assert(is_objArray_klass(), "sanity");
  }
  
  size_t ObjArrayKlass::oop_size(oop obj) const {
--- 128,22 ---
  
    if (element_klass->is_array_klass()) {
      set_lower_dimension(ArrayKlass::cast(element_klass));
    }
  
!   int lh = array_layout_helper(T_OBJECT);
+   if (null_free) {
+     assert(n == 1, "Bytecode does not support null-free multi-dim");
+     lh = layout_helper_set_null_free(lh);
+ #ifdef _LP64
+     set_prototype_header(markWord::null_free_array_prototype());
+     assert(prototype_header().is_null_free_array(), "sanity");
+ #else
+     set_prototype_header(markWord::inline_type_prototype());
+ #endif
+   }
+   set_layout_helper(lh);
    assert(is_array_klass(), "sanity");
    assert(is_objArray_klass(), "sanity");
  }
  
  size_t ObjArrayKlass::oop_size(oop obj) const {

*** 148,12 ***
  }
  
  objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
    check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
    size_t size = objArrayOopDesc::object_size(length);
!   return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
!                                                        /* do_zero */ true, THREAD);
  }
  
  oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
    int length = *sizes;
    ArrayKlass* ld_klass = lower_dimension();
--- 152,27 ---
  }
  
  objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
    check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
    size_t size = objArrayOopDesc::object_size(length);
!   bool populate_null_free = is_null_free_array_klass();
!   objArrayOop array =  (objArrayOop)Universe::heap()->array_allocate(this, size, length,
+                                                        /* do_zero */ true, CHECK_NULL);
+   objArrayHandle array_h(THREAD, array);
+   if (populate_null_free) {
+     assert(dimension() == 1, "Can only populate the final dimension");
+     assert(element_klass()->is_inline_klass(), "Unexpected");
+     assert(!element_klass()->is_array_klass(), "ArrayKlass unexpected here");
+     assert(!InlineKlass::cast(element_klass())->flat_array(), "Expected flatArrayOop allocation");
+     element_klass()->initialize(CHECK_NULL);
+     // Populate default values...
+     instanceOop value = (instanceOop) InlineKlass::cast(element_klass())->default_value();
+     for (int i = 0; i < length; i++) {
+       array_h->obj_at_put(i, value);
+     }
+   }
+   return array_h();
  }
  
  oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
    int length = *sizes;
    ArrayKlass* ld_klass = lower_dimension();

*** 161,11 ***
    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
--- 180,11 ---
    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

*** 190,39 ***
      ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
    } else {
      // We have to make sure all elements conform to the destination array
      Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
      Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
      if (stype == bound || stype->is_subtype_of(bound)) {
!       // elements are guaranteed to be subtypes, so no check necessary
!       ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
      } else {
!       // slow case: need individual subtype checks
!       // note: don't use obj_at_put below because it includes a redundant store check
!       if (!ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length)) {
!         ResourceMark rm(THREAD);
-         stringStream ss;
-         if (!bound->is_subtype_of(stype)) {
-           ss.print("arraycopy: type mismatch: can not copy %s[] into %s[]",
-                    stype->external_name(), bound->external_name());
-         } else {
-           // oop_arraycopy should return the index in the source array that
-           // contains the problematic oop.
-           ss.print("arraycopy: element type mismatch: can not cast one of the elements"
-                    " of %s[] to the type of the destination array, %s",
-                    stype->external_name(), bound->external_name());
-         }
-         THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string());
        }
      }
    }
  }
  
  void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
                                 int dst_pos, int length, TRAPS) {
    assert(s->is_objArray(), "must be obj array");
  
    if (!d->is_objArray()) {
      ResourceMark rm(THREAD);
      stringStream ss;
      if (d->is_typeArray()) {
        ss.print("arraycopy: type mismatch: can not copy object array[] into %s[]",
--- 209,40 ---
      ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
    } else {
      // We have to make sure all elements conform to the destination array
      Klass* bound = ObjArrayKlass::cast(d->klass())->element_klass();
      Klass* stype = ObjArrayKlass::cast(s->klass())->element_klass();
+     // Perform null check if dst is null-free but src has no such guarantee
+     bool null_check = ((!s->klass()->is_null_free_array_klass()) &&
+         d->klass()->is_null_free_array_klass());
      if (stype == bound || stype->is_subtype_of(bound)) {
!       if (null_check) {
!         ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length);
+       } else {
+         ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
+       }
      } else {
!       if (null_check) {
!         ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST | ARRAYCOPY_NOTNULL>::oop_arraycopy(s, src_offset, d, dst_offset, length);
!       } else {
!         ArrayAccess<ARRAYCOPY_DISJOINT | ARRAYCOPY_CHECKCAST>::oop_arraycopy(s, src_offset, d, dst_offset, length);
        }
      }
    }
  }
  
  void ObjArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
                                 int dst_pos, int length, TRAPS) {
    assert(s->is_objArray(), "must be obj array");
  
+   if (UseFlatArray) {
+     if (d->is_flatArray()) {
+       FlatArrayKlass::cast(d->klass())->copy_array(s, src_pos, d, dst_pos, length, THREAD);
+       return;
+     }
+   }
+ 
    if (!d->is_objArray()) {
      ResourceMark rm(THREAD);
      stringStream ss;
      if (d->is_typeArray()) {
        ss.print("arraycopy: type mismatch: can not copy object array[] into %s[]",

*** 335,19 ***
    it->push(&_bottom_klass);
  }
  
  jint ObjArrayKlass::compute_modifier_flags() const {
    // The modifier for an objectArray is the same as its element
    if (element_klass() == nullptr) {
      assert(Universe::is_bootstrapping(), "partial objArray only at startup");
      return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
    }
    // Return the flags of the bottom element type.
    jint element_flags = bottom_klass()->compute_modifier_flags();
  
    return (element_flags & (JVM_ACC_PUBLIC | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED))
!                         | (JVM_ACC_ABSTRACT | JVM_ACC_FINAL);
  }
  
  ModuleEntry* ObjArrayKlass::module() const {
    assert(bottom_klass() != nullptr, "ObjArrayKlass returned unexpected null bottom_klass");
    // The array is defined in the module of its bottom class
--- 355,22 ---
    it->push(&_bottom_klass);
  }
  
  jint ObjArrayKlass::compute_modifier_flags() const {
    // The modifier for an objectArray is the same as its element
+   // With the addition of ACC_IDENTITY
    if (element_klass() == nullptr) {
      assert(Universe::is_bootstrapping(), "partial objArray only at startup");
      return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC;
    }
    // Return the flags of the bottom element type.
    jint element_flags = bottom_klass()->compute_modifier_flags();
  
+   int identity_flag = (Arguments::enable_preview()) ? JVM_ACC_IDENTITY : 0;
+ 
    return (element_flags & (JVM_ACC_PUBLIC | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED))
!                         | (identity_flag | JVM_ACC_ABSTRACT | JVM_ACC_FINAL);
  }
  
  ModuleEntry* ObjArrayKlass::module() const {
    assert(bottom_klass() != nullptr, "ObjArrayKlass returned unexpected null bottom_klass");
    // The array is defined in the module of its bottom class

*** 362,11 ***
  // Printing
  
  void ObjArrayKlass::print_on(outputStream* st) const {
  #ifndef PRODUCT
    Klass::print_on(st);
!   st->print(" - instance klass: ");
    element_klass()->print_value_on(st);
    st->cr();
  #endif //PRODUCT
  }
  
--- 385,11 ---
  // Printing
  
  void ObjArrayKlass::print_on(outputStream* st) const {
  #ifndef PRODUCT
    Klass::print_on(st);
!   st->print(" - element klass: ");
    element_klass()->print_value_on(st);
    st->cr();
  #endif //PRODUCT
  }
  

*** 424,16 ***
  void ObjArrayKlass::verify_on(outputStream* st) {
    ArrayKlass::verify_on(st);
    guarantee(element_klass()->is_klass(), "should be klass");
    guarantee(bottom_klass()->is_klass(), "should be klass");
    Klass* bk = bottom_klass();
!   guarantee(bk->is_instance_klass() || bk->is_typeArray_klass(),  "invalid bottom klass");
  }
  
  void ObjArrayKlass::oop_verify_on(oop obj, outputStream* st) {
    ArrayKlass::oop_verify_on(obj, st);
    guarantee(obj->is_objArray(), "must be objArray");
    objArrayOop oa = objArrayOop(obj);
    for(int index = 0; index < oa->length(); index++) {
      guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop");
    }
  }
--- 447,18 ---
  void ObjArrayKlass::verify_on(outputStream* st) {
    ArrayKlass::verify_on(st);
    guarantee(element_klass()->is_klass(), "should be klass");
    guarantee(bottom_klass()->is_klass(), "should be klass");
    Klass* bk = bottom_klass();
!   guarantee(bk->is_instance_klass() || bk->is_typeArray_klass() || bk->is_flatArray_klass(),
+             "invalid bottom klass");
  }
  
  void ObjArrayKlass::oop_verify_on(oop obj, outputStream* st) {
    ArrayKlass::oop_verify_on(obj, st);
    guarantee(obj->is_objArray(), "must be objArray");
+   guarantee(obj->is_null_free_array() || (!is_null_free_array_klass()), "null-free klass but not object");
    objArrayOop oa = objArrayOop(obj);
    for(int index = 0; index < oa->length(); index++) {
      guarantee(oopDesc::is_oop_or_null(oa->obj_at(index)), "should be oop");
    }
  }
< prev index next >