< 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.inline.hpp"
  #include "oops/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"

@@ -43,29 +44,37 @@
  #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) {
+ 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);
+   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, TRAPS) {
+                                                       int n, Klass* element_klass,
+                                                       bool null_free, bool qdesc, TRAPS) {
+   assert(!null_free || (n == 1 && element_klass->is_inline_klass() && qdesc), "null-free unsupported");
  
    // Eagerly allocate the direct array supertype.
    Klass* super_klass = NULL;
    if (!Universe::is_bootstrapping() || vmClasses::Object_klass_loaded()) {
      Klass* element_super = element_klass->super();
      if (element_super != NULL) {
        // The element type has a direct super.  E.g., String[] has direct super of Object[].
-       super_klass = element_super->array_klass_or_null();
+       if (null_free) {
+         super_klass = element_klass->array_klass_or_null();
+       } else {
+         super_klass = element_super->array_klass_or_null();
+       }
        bool supers_exist = super_klass != NULL;
        // Also, see if the element has secondary supertypes.
        // We need an array type for each.
        const Array<Klass*>* element_supers = element_klass->secondary_supers();
        for( int i = element_supers->length()-1; i >= 0; i-- ) {

@@ -73,54 +82,49 @@
          if (elem_super->array_klass_or_null() == NULL) {
            supers_exist = false;
            break;
          }
        }
+       if (null_free) {
+         if (element_klass->array_klass_or_null() == NULL) {
+           supers_exist = false;
+         }
+       }
        if (!supers_exist) {
          // Oops.  Not allocated yet.  Back out, allocate it, and retry.
          Klass* ek = NULL;
          {
            MutexUnlocker mu(MultiArray_lock);
-           super_klass = element_super->array_klass(CHECK_NULL);
+           if (null_free) {
+             element_klass->array_klass(CHECK_NULL);
+           } else {
+             element_super->array_klass(CHECK_NULL);
+           }
            for( int i = element_supers->length()-1; i >= 0; i-- ) {
              Klass* elem_super = element_supers->at(i);
              elem_super->array_klass(CHECK_NULL);
            }
            // Now retry from the beginning
-           ek = element_klass->array_klass(n, CHECK_NULL);
+           if (null_free) {
+             ek = InlineKlass::cast(element_klass)->null_free_inline_array_klass(CHECK_NULL);
+           } else {
+             ek = element_klass->array_klass(n, CHECK_NULL);
+           }
          }  // re-lock
          return ObjArrayKlass::cast(ek);
        }
      } else {
        // The element type is already Object.  Object[] has direct super of Object.
        super_klass = vmClasses::Object_klass();
      }
    }
  
    // Create type name for klass.
-   Symbol* name = NULL;
-   {
-     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);
-   }
+   Symbol* name = ArrayKlass::create_element_klass_array_name(element_klass, qdesc, CHECK_NULL);
  
    // Initialize instance variables
-   ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, CHECK_NULL);
+   ObjArrayKlass* oak = ObjArrayKlass::allocate(loader_data, n, element_klass, name, null_free, CHECK_NULL);
  
    ModuleEntry* module = oak->module();
    assert(module != NULL, "No module entry for array");
  
    // Call complete_create_array_klass after all instance variables has been initialized.

@@ -134,25 +138,40 @@
    loader_data->add_class(oak);
  
    return oak;
  }
  
- ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, ID) {
+ ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name, bool null_free) : ArrayKlass(name, ID) {
    set_dimension(n);
    set_element_klass(element_klass);
  
+   assert(!null_free || name->is_Q_array_signature(), "sanity check");
+ 
    Klass* bk;
    if (element_klass->is_objArray_klass()) {
      bk = ObjArrayKlass::cast(element_klass)->bottom_klass();
+   } else if (element_klass->is_flatArray_klass()) {
+     bk = FlatArrayKlass::cast(element_klass)->element_klass();
    } else {
      bk = element_klass;
    }
    assert(bk != NULL && (bk->is_instance_klass() || bk->is_typeArray_klass()), "invalid bottom klass");
    set_bottom_klass(bk);
    set_class_loader_data(bk->class_loader_data());
  
-   set_layout_helper(array_layout_helper(T_OBJECT));
+   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");
  }
  
  int ObjArrayKlass::oop_size(oop obj) const {

@@ -161,40 +180,59 @@
  }
  
  objArrayOop ObjArrayKlass::allocate(int length, TRAPS) {
    check_array_allocation_length(length, arrayOopDesc::max_array_length(T_OBJECT), CHECK_NULL);
    int size = objArrayOopDesc::object_size(length);
-   return (objArrayOop)Universe::heap()->array_allocate(this, size, length,
+   bool populate_null_free = is_null_free_array_klass();
+   objArrayOop array =  (objArrayOop)Universe::heap()->array_allocate(this, size, length,
                                                         /* do_zero */ true, THREAD);
+   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())->flatten_array(), "Expected flatArrayOop allocation");
+     element_klass()->initialize(CHECK_NULL);
+     // Populate default values...
+     objArrayHandle array_h(THREAD, array);
+     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;
  }
  
- static int multi_alloc_counter = 0;
- 
  oop ObjArrayKlass::multi_allocate(int rank, jint* sizes, TRAPS) {
    int length = *sizes;
+   if (rank == 1) { // last dim may be flatArray, check if we have any special storage requirements
+     if (name()->char_at(1) != JVM_SIGNATURE_ARRAY &&  name()->is_Q_array_signature()) {
+       return oopFactory::new_flatArray(element_klass(), length, CHECK_NULL);
+     } else {
+       return oopFactory::new_objArray(element_klass(), length, CHECK_NULL);
+     }
+   }
+   guarantee(rank > 1, "Rank below 1");
    // Call to lower_dimension uses this pointer, so most be called before a
    // possible GC
    Klass* 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++) {
-         ArrayKlass* ak = ArrayKlass::cast(ld_klass);
-         oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
-         h_array->obj_at_put(index, sub_array);
-       }
-     } else {
-       // Since this array dimension has zero length, nothing will be
-       // allocated, however the lower dimension values must be checked
-       // for illegal values.
-       for (int i = 0; i < rank - 1; ++i) {
-         sizes += 1;
-         if (*sizes < 0) {
-           THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes));
-         }
+   if (length != 0) {
+     for (int index = 0; index < length; index++) {
+       ArrayKlass* ak = ArrayKlass::cast(ld_klass);
+       oop sub_array = ak->multi_allocate(rank-1, &sizes[1], CHECK_NULL);
+       h_array->obj_at_put(index, sub_array);
+     }
+   } else {
+     // Since this array dimension has zero length, nothing will be
+     // allocated, however the lower dimension values must be checked
+     // for illegal values.
+     for (int i = 0; i < rank - 1; ++i) {
+       sizes += 1;
+       if (*sizes < 0) {
+         THROW_MSG_0(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", *sizes));
        }
      }
    }
    return h_array();
  }

@@ -208,39 +246,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)) {
-       // elements are guaranteed to be subtypes, so no check necessary
-       ArrayAccess<ARRAYCOPY_DISJOINT>::oop_arraycopy(s, src_offset, d, dst_offset, length);
+       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 {
-       // 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());
+       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 (EnableValhalla) {
+     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[]",

@@ -309,11 +348,10 @@
    }
  }
  
  
  Klass* ObjArrayKlass::array_klass(int n, TRAPS) {
- 
    assert(dimension() <= n, "check order of chain");
    int dim = dimension();
    if (dim == n) return this;
  
    // lock-free read needs acquire semantics

@@ -326,12 +364,12 @@
  
        // Check if another thread beat us
        if (higher_dimension() == NULL) {
  
          // Create multi-dim klass object and link them together
-         Klass* k =
-           ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this, CHECK_NULL);
+         Klass* k = ObjArrayKlass::allocate_objArray_klass(class_loader_data(), dim + 1, this,
+                                                           false, this->name()->is_Q_array_signature(), CHECK_NULL);
          ObjArrayKlass* ak = ObjArrayKlass::cast(k);
          ak->set_lower_dimension(this);
          // use 'release' to pair with lock-free load
          release_set_higher_dimension(ak);
          assert(ak->is_objArray_klass(), "incorrect initialization of ObjArrayKlass");

@@ -385,13 +423,14 @@
    if (num_secondaries == 2) {
      // Must share this for correct bootstrapping!
      set_secondary_supers(Universe::the_array_interfaces_array());
      return NULL;
    } else {
-     GrowableArray<Klass*>* secondaries = new GrowableArray<Klass*>(num_elem_supers+2);
+     GrowableArray<Klass*>* secondaries = new GrowableArray<Klass*>(num_elem_supers+3);
      secondaries->push(vmClasses::Cloneable_klass());
      secondaries->push(vmClasses::Serializable_klass());
+     secondaries->push(vmClasses::IdentityObject_klass());
      for (int i = 0; i < num_elem_supers; i++) {
        Klass* elem_super = elem_supers->at(i);
        Klass* array_super = elem_super->array_klass_or_null();
        assert(array_super != NULL, "must already have been created");
        secondaries->push(array_super);

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

@@ -499,16 +538,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(),  "invalid 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 >