< prev index next >

src/hotspot/share/opto/type.cpp

Print this page
*** 20,11 ***
--- 20,15 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   *
   */
  
+ #include "ci/ciField.hpp"
+ #include "ci/ciFlatArrayKlass.hpp"
+ #include "ci/ciInlineKlass.hpp"
  #include "ci/ciMethodData.hpp"
+ #include "ci/ciObjArrayKlass.hpp"
  #include "ci/ciTypeFlow.hpp"
  #include "classfile/javaClasses.hpp"
  #include "classfile/symbolTable.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "compiler/compileLog.hpp"

*** 41,23 ***
--- 45,70 ---
  #include "opto/node.hpp"
  #include "opto/opcodes.hpp"
  #include "opto/rangeinference.hpp"
  #include "opto/runtime.hpp"
  #include "opto/type.hpp"
+ #include "runtime/globals.hpp"
  #include "runtime/stubRoutines.hpp"
  #include "utilities/checkedCast.hpp"
  #include "utilities/debug.hpp"
+ #include "utilities/globalDefinitions.hpp"
  #include "utilities/ostream.hpp"
  #include "utilities/powerOfTwo.hpp"
  #include "utilities/stringUtils.hpp"
  
  // Portions of code courtesy of Clifford Click
  
  // Optimization - Graph Style
  
  // Dictionary of types shared among compilations.
  Dict* Type::_shared_type_dict = nullptr;
+ const Type::Offset Type::Offset::top(Type::OffsetTop);
+ const Type::Offset Type::Offset::bottom(Type::OffsetBot);
+ 
+ const Type::Offset Type::Offset::meet(const Type::Offset other) const {
+   // Either is 'TOP' offset?  Return the other offset!
+   if (_offset == OffsetTop) return other;
+   if (other._offset == OffsetTop) return *this;
+   // If either is different, return 'BOTTOM' offset
+   if (_offset != other._offset) return bottom;
+   return Offset(_offset);
+ }
+ 
+ const Type::Offset Type::Offset::dual() const {
+   if (_offset == OffsetTop) return bottom;// Map 'TOP' into 'BOTTOM'
+   if (_offset == OffsetBot) return top;// Map 'BOTTOM' into 'TOP'
+   return Offset(_offset);               // Map everything else into self
+ }
+ 
+ const Type::Offset Type::Offset::add(intptr_t offset) const {
+   // Adding to 'TOP' offset?  Return 'TOP'!
+   if (_offset == OffsetTop || offset == OffsetTop) return top;
+   // Adding to 'BOTTOM' offset?  Return 'BOTTOM'!
+   if (_offset == OffsetBot || offset == OffsetBot) return bottom;
+   // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'!
+   offset += (intptr_t)_offset;
+   if (offset != (int)offset || offset == OffsetTop) return bottom;
+ 
+   // assert( _offset >= 0 && _offset+offset >= 0, "" );
+   // It is possible to construct a negative offset during PhaseCCP
+ 
+   return Offset((int)offset);        // Sum valid offsets
+ }
+ 
+ void Type::Offset::dump2(outputStream *st) const {
+   if (_offset == 0) {
+     return;
+   } else if (_offset == OffsetTop) {
+     st->print("+top");
+   }
+   else if (_offset == OffsetBot) {
+     st->print("+bot");
+   } else if (_offset) {
+     st->print("+%d", _offset);
+   }
+ }
  
  // Array which maps compiler types to Basic Types
  const Type::TypeInfo Type::_type_info[Type::lastype] = {
    { Bad,             T_ILLEGAL,    "bad",           false, Node::NotAMachineReg, relocInfo::none          },  // Bad
    { Control,         T_ILLEGAL,    "control",       false, 0,                    relocInfo::none          },  // Control

*** 232,10 ***
--- 283,13 ---
  
    case T_ADDRESS:
      assert(type->is_return_address(), "");
      return TypeRawPtr::make((address)(intptr_t)type->as_return_address()->bci());
  
+   case T_OBJECT:
+     return Type::get_const_type(type->unwrap())->join_speculative(type->is_null_free() ? TypePtr::NOTNULL : TypePtr::BOTTOM);
+ 
    default:
      // make sure we did not mix up the cases:
      assert(type != ciTypeFlow::StateVector::bottom_type(), "");
      assert(type != ciTypeFlow::StateVector::top_type(), "");
      assert(type != ciTypeFlow::StateVector::null_type(), "");

*** 554,13 ***
    const Type **floop =(const Type**)shared_type_arena->AmallocWords(2*sizeof(Type*));
    floop[0] = Type::CONTROL;
    floop[1] = TypeInt::INT;
    TypeTuple::LOOPBODY = TypeTuple::make( 2, floop );
  
!   TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, 0);
!   TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, OffsetBot);
!   TypePtr::BOTTOM  = TypePtr::make(AnyPtr, TypePtr::BotPTR, OffsetBot);
  
    TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR );
    TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull );
  
    const Type **fmembar = TypeTuple::fields(0);
--- 608,13 ---
    const Type **floop =(const Type**)shared_type_arena->AmallocWords(2*sizeof(Type*));
    floop[0] = Type::CONTROL;
    floop[1] = TypeInt::INT;
    TypeTuple::LOOPBODY = TypeTuple::make( 2, floop );
  
!   TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, Offset(0));
!   TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, Offset::bottom);
!   TypePtr::BOTTOM  = TypePtr::make(AnyPtr, TypePtr::BotPTR, Offset::bottom);
  
    TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR );
    TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull );
  
    const Type **fmembar = TypeTuple::fields(0);

*** 573,16 ***
  
    TypeInstPtr::NOTNULL = TypeInstPtr::make(TypePtr::NotNull, current->env()->Object_klass());
    TypeInstPtr::BOTTOM  = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass());
    TypeInstPtr::MIRROR  = TypeInstPtr::make(TypePtr::NotNull, current->env()->Class_klass());
    TypeInstPtr::MARK    = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
!                                            false, nullptr, oopDesc::mark_offset_in_bytes());
    TypeInstPtr::KLASS   = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
!                                            false, nullptr, oopDesc::klass_offset_in_bytes());
!   TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
  
!   TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, nullptr, OffsetBot);
  
    TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR );
    TypeNarrowOop::BOTTOM   = TypeNarrowOop::make( TypeInstPtr::BOTTOM );
  
    TypeNarrowKlass::NULL_PTR = TypeNarrowKlass::make( TypePtr::NULL_PTR );
--- 627,16 ---
  
    TypeInstPtr::NOTNULL = TypeInstPtr::make(TypePtr::NotNull, current->env()->Object_klass());
    TypeInstPtr::BOTTOM  = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass());
    TypeInstPtr::MIRROR  = TypeInstPtr::make(TypePtr::NotNull, current->env()->Class_klass());
    TypeInstPtr::MARK    = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
!                                            false, nullptr, Offset(oopDesc::mark_offset_in_bytes()));
    TypeInstPtr::KLASS   = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
!                                            false, nullptr, Offset(oopDesc::klass_offset_in_bytes()));
!   TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, Offset::bottom, TypeOopPtr::InstanceBot);
  
!   TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, nullptr, Offset::bottom);
  
    TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR );
    TypeNarrowOop::BOTTOM   = TypeNarrowOop::make( TypeInstPtr::BOTTOM );
  
    TypeNarrowKlass::NULL_PTR = TypeNarrowKlass::make( TypePtr::NULL_PTR );

*** 601,48 ***
    array_interfaces.push(current->env()->Cloneable_klass());
    array_interfaces.push(current->env()->Serializable_klass());
    TypeAryPtr::_array_interfaces = TypeInterfaces::make(&array_interfaces);
    TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces;
  
!   TypeAryPtr::BOTTOM = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS), nullptr, false, Type::OffsetBot);
!   TypeAryPtr::RANGE   = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), nullptr /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes());
  
!   TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), nullptr /*ciArrayKlass::make(o)*/,  false,  Type::OffsetBot);
  
  #ifdef _LP64
    if (UseCompressedOops) {
      assert(TypeAryPtr::NARROWOOPS->is_ptr_to_narrowoop(), "array of narrow oops must be ptr to narrow oop");
      TypeAryPtr::OOPS  = TypeAryPtr::NARROWOOPS;
    } else
  #endif
    {
      // There is no shared klass for Object[].  See note in TypeAryPtr::klass().
!     TypeAryPtr::OOPS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), nullptr /*ciArrayKlass::make(o)*/,  false,  Type::OffsetBot);
    }
!   TypeAryPtr::BYTES   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE      ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE),   true,  Type::OffsetBot);
!   TypeAryPtr::SHORTS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT     ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT),  true,  Type::OffsetBot);
!   TypeAryPtr::CHARS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR      ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR),   true,  Type::OffsetBot);
!   TypeAryPtr::INTS    = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT       ,TypeInt::POS), ciTypeArrayKlass::make(T_INT),    true,  Type::OffsetBot);
!   TypeAryPtr::LONGS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG     ,TypeInt::POS), ciTypeArrayKlass::make(T_LONG),   true,  Type::OffsetBot);
!   TypeAryPtr::FLOATS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT        ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT),  true,  Type::OffsetBot);
!   TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE       ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true,  Type::OffsetBot);
  
    // Nobody should ask _array_body_type[T_NARROWOOP]. Use null as assert.
    TypeAryPtr::_array_body_type[T_NARROWOOP] = nullptr;
    TypeAryPtr::_array_body_type[T_OBJECT]  = TypeAryPtr::OOPS;
    TypeAryPtr::_array_body_type[T_ARRAY]   = TypeAryPtr::OOPS; // arrays are stored in oop arrays
    TypeAryPtr::_array_body_type[T_BYTE]    = TypeAryPtr::BYTES;
    TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES;  // boolean[] is a byte array
    TypeAryPtr::_array_body_type[T_SHORT]   = TypeAryPtr::SHORTS;
    TypeAryPtr::_array_body_type[T_CHAR]    = TypeAryPtr::CHARS;
    TypeAryPtr::_array_body_type[T_INT]     = TypeAryPtr::INTS;
    TypeAryPtr::_array_body_type[T_LONG]    = TypeAryPtr::LONGS;
    TypeAryPtr::_array_body_type[T_FLOAT]   = TypeAryPtr::FLOATS;
    TypeAryPtr::_array_body_type[T_DOUBLE]  = TypeAryPtr::DOUBLES;
  
!   TypeInstKlassPtr::OBJECT = TypeInstKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), 0);
!   TypeInstKlassPtr::OBJECT_OR_NULL = TypeInstKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), 0);
  
    const Type **fi2c = TypeTuple::fields(2);
    fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method*
    fi2c[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // argument pointer
    TypeTuple::START_I2C = TypeTuple::make(TypeFunc::Parms+2, fi2c);
--- 655,50 ---
    array_interfaces.push(current->env()->Cloneable_klass());
    array_interfaces.push(current->env()->Serializable_klass());
    TypeAryPtr::_array_interfaces = TypeInterfaces::make(&array_interfaces);
    TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces;
  
!   TypeAryPtr::BOTTOM = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS, false, false, false, false, false), nullptr, false, Offset::bottom);
!   TypeAryPtr::RANGE   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS, false, false, false, false, false), nullptr /* current->env()->Object_klass() */, false, Offset(arrayOopDesc::length_offset_in_bytes()));
  
!   TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/,  false,  Offset::bottom);
  
  #ifdef _LP64
    if (UseCompressedOops) {
      assert(TypeAryPtr::NARROWOOPS->is_ptr_to_narrowoop(), "array of narrow oops must be ptr to narrow oop");
      TypeAryPtr::OOPS  = TypeAryPtr::NARROWOOPS;
    } else
  #endif
    {
      // There is no shared klass for Object[].  See note in TypeAryPtr::klass().
!     TypeAryPtr::OOPS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, false, false, false, false, false), nullptr /*ciArrayKlass::make(o)*/,  false,  Offset::bottom);
    }
!   TypeAryPtr::BYTES   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE      ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_BYTE),   true,  Offset::bottom);
!   TypeAryPtr::SHORTS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT     ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_SHORT),  true,  Offset::bottom);
!   TypeAryPtr::CHARS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR      ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_CHAR),   true,  Offset::bottom);
!   TypeAryPtr::INTS    = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT       ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_INT),    true,  Offset::bottom);
!   TypeAryPtr::LONGS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG     ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_LONG),   true,  Offset::bottom);
!   TypeAryPtr::FLOATS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT        ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_FLOAT),  true,  Offset::bottom);
!   TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE       ,TypeInt::POS, false, false, true, true, true), ciTypeArrayKlass::make(T_DOUBLE), true,  Offset::bottom);
+   TypeAryPtr::INLINES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS, /* stable= */ false, /* flat= */ true, false, false, false), nullptr, false, Offset::bottom);
  
    // Nobody should ask _array_body_type[T_NARROWOOP]. Use null as assert.
    TypeAryPtr::_array_body_type[T_NARROWOOP] = nullptr;
    TypeAryPtr::_array_body_type[T_OBJECT]  = TypeAryPtr::OOPS;
+   TypeAryPtr::_array_body_type[T_FLAT_ELEMENT] = TypeAryPtr::OOPS;
    TypeAryPtr::_array_body_type[T_ARRAY]   = TypeAryPtr::OOPS; // arrays are stored in oop arrays
    TypeAryPtr::_array_body_type[T_BYTE]    = TypeAryPtr::BYTES;
    TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES;  // boolean[] is a byte array
    TypeAryPtr::_array_body_type[T_SHORT]   = TypeAryPtr::SHORTS;
    TypeAryPtr::_array_body_type[T_CHAR]    = TypeAryPtr::CHARS;
    TypeAryPtr::_array_body_type[T_INT]     = TypeAryPtr::INTS;
    TypeAryPtr::_array_body_type[T_LONG]    = TypeAryPtr::LONGS;
    TypeAryPtr::_array_body_type[T_FLOAT]   = TypeAryPtr::FLOATS;
    TypeAryPtr::_array_body_type[T_DOUBLE]  = TypeAryPtr::DOUBLES;
  
!   TypeInstKlassPtr::OBJECT = TypeInstKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), Offset(0));
!   TypeInstKlassPtr::OBJECT_OR_NULL = TypeInstKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), Offset(0));
  
    const Type **fi2c = TypeTuple::fields(2);
    fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method*
    fi2c[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // argument pointer
    TypeTuple::START_I2C = TypeTuple::make(TypeFunc::Parms+2, fi2c);

*** 677,10 ***
--- 733,11 ---
    _const_basic_type[T_LONG]        = TypeLong::LONG;
    _const_basic_type[T_FLOAT]       = Type::FLOAT;
    _const_basic_type[T_DOUBLE]      = Type::DOUBLE;
    _const_basic_type[T_OBJECT]      = TypeInstPtr::BOTTOM;
    _const_basic_type[T_ARRAY]       = TypeInstPtr::BOTTOM; // there is no separate bottom for arrays
+   _const_basic_type[T_FLAT_ELEMENT] = TypeInstPtr::BOTTOM;
    _const_basic_type[T_VOID]        = TypePtr::NULL_PTR;   // reflection represents void this way
    _const_basic_type[T_ADDRESS]     = TypeRawPtr::BOTTOM;  // both interpreter return addresses & random raw ptrs
    _const_basic_type[T_CONFLICT]    = Type::BOTTOM;        // why not?
  
    _zero_type[T_NARROWOOP]   = TypeNarrowOop::NULL_PTR;

*** 693,10 ***
--- 750,11 ---
    _zero_type[T_LONG]        = TypeLong::ZERO;
    _zero_type[T_FLOAT]       = TypeF::ZERO;
    _zero_type[T_DOUBLE]      = TypeD::ZERO;
    _zero_type[T_OBJECT]      = TypePtr::NULL_PTR;
    _zero_type[T_ARRAY]       = TypePtr::NULL_PTR; // null array is null oop
+   _zero_type[T_FLAT_ELEMENT] = TypePtr::NULL_PTR;
    _zero_type[T_ADDRESS]     = TypePtr::NULL_PTR; // raw pointers use the same null
    _zero_type[T_VOID]        = Type::TOP;         // the only void value is no value at all
  
    // get_zero_type() should not happen for T_CONFLICT
    _zero_type[T_CONFLICT]= nullptr;

*** 967,10 ***
--- 1025,13 ---
  };
  
  void Type::check_symmetrical(const Type* t, const Type* mt, const VerifyMeet& verify) const {
    Compile* C = Compile::current();
    const Type* mt2 = verify.meet(t, this);
+ 
+   // Verify that:
+   //      this meet t == t meet this
    if (mt != mt2) {
      tty->print_cr("=== Meet Not Commutative ===");
      tty->print("t           = ");   t->dump(); tty->cr();
      tty->print("this        = ");      dump(); tty->cr();
      tty->print("t meet this = "); mt2->dump(); tty->cr();

*** 983,22 ***
--- 1044,42 ---
  
    // Interface meet Oop is Not Symmetric:
    // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull
    // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull
  
+   // Verify that:
+   // 1)     mt_dual meet t_dual    == t_dual
+   //    which corresponds to
+   //       !(t meet this)  meet !t ==
+   //       (!t join !this) meet !t == !t
+   // 2)    mt_dual meet this_dual     == this_dual
+   //    which corresponds to
+   //       !(t meet this)  meet !this ==
+   //       (!t join !this) meet !this == !this
    if (t2t != t->_dual || t2this != this->_dual) {
      tty->print_cr("=== Meet Not Symmetric ===");
      tty->print("t   =                   ");              t->dump(); tty->cr();
      tty->print("this=                   ");                 dump(); tty->cr();
      tty->print("mt=(t meet this)=       ");             mt->dump(); tty->cr();
  
      tty->print("t_dual=                 ");       t->_dual->dump(); tty->cr();
      tty->print("this_dual=              ");          _dual->dump(); tty->cr();
      tty->print("mt_dual=                ");      mt->_dual->dump(); tty->cr();
  
+     // 1)
      tty->print("mt_dual meet t_dual=    "); t2t           ->dump(); tty->cr();
+     // 2)
      tty->print("mt_dual meet this_dual= "); t2this        ->dump(); tty->cr();
+     tty->cr();
+     tty->print_cr("Fail: ");
+     if (t2t != t->_dual) {
+       tty->print_cr("- mt_dual meet t_dual != t_dual");
+     }
+     if (t2this != this->_dual) {
+       tty->print_cr("- mt_dual meet this_dual != this_dual");
+     }
+     tty->cr();
  
      fatal("meet not symmetric");
    }
  }
  #endif

*** 1031,10 ***
--- 1112,13 ---
      return mt;
    }
    if (isa_narrowklass() || t->isa_narrowklass()) {
      return mt;
    }
+   // TODO 8350865 This currently triggers a verification failure, the code around "// Even though MyValue is final" needs adjustments
+   if ((this_t->isa_ptr() && this_t->is_ptr()->is_not_flat()) ||
+       (this_t->_dual->isa_ptr() && this_t->_dual->is_ptr()->is_not_flat())) return mt;
    this_t->check_symmetrical(t, mt, verify);
    const Type *mt_dual = verify.meet(this_t->_dual, t->_dual);
    this_t->_dual->check_symmetrical(t->_dual, mt_dual, verify);
  #endif
    return mt;

*** 2047,15 ***
  const TypeTuple *TypeTuple::INT_PAIR;
  const TypeTuple *TypeTuple::LONG_PAIR;
  const TypeTuple *TypeTuple::INT_CC_PAIR;
  const TypeTuple *TypeTuple::LONG_CC_PAIR;
  
  //------------------------------make-------------------------------------------
  // Make a TypeTuple from the range of a method signature
! const TypeTuple *TypeTuple::make_range(ciSignature* sig, InterfaceHandling interface_handling) {
    ciType* return_type = sig->return_type();
    uint arg_cnt = return_type->size();
    const Type **field_array = fields(arg_cnt);
    switch (return_type->basic_type()) {
    case T_LONG:
      field_array[TypeFunc::Parms]   = TypeLong::LONG;
      field_array[TypeFunc::Parms+1] = Type::HALF;
--- 2131,41 ---
  const TypeTuple *TypeTuple::INT_PAIR;
  const TypeTuple *TypeTuple::LONG_PAIR;
  const TypeTuple *TypeTuple::INT_CC_PAIR;
  const TypeTuple *TypeTuple::LONG_CC_PAIR;
  
+ static void collect_inline_fields(ciInlineKlass* vk, const Type** field_array, uint& pos) {
+   for (int i = 0; i < vk->nof_declared_nonstatic_fields(); i++) {
+     ciField* field = vk->declared_nonstatic_field_at(i);
+     if (field->is_flat()) {
+       collect_inline_fields(field->type()->as_inline_klass(), field_array, pos);
+       if (!field->is_null_free()) {
+         // Use T_INT instead of T_BOOLEAN here because the upper bits can contain garbage if the holder
+         // is null and C2 will only zero them for T_INT assuming that T_BOOLEAN is already canonicalized.
+         field_array[pos++] = Type::get_const_basic_type(T_INT);
+       }
+     } else {
+       BasicType bt = field->type()->basic_type();
+       const Type* ft = Type::get_const_type(field->type());
+       field_array[pos++] = ft;
+       if (type2size[bt] == 2) {
+         field_array[pos++] = Type::HALF;
+       }
+     }
+   }
+ }
+ 
  //------------------------------make-------------------------------------------
  // Make a TypeTuple from the range of a method signature
! const TypeTuple *TypeTuple::make_range(ciSignature* sig, InterfaceHandling interface_handling, bool ret_vt_fields) {
    ciType* return_type = sig->return_type();
    uint arg_cnt = return_type->size();
+   if (ret_vt_fields) {
+     arg_cnt = return_type->as_inline_klass()->inline_arg_slots() + 1;
+     // InlineTypeNode::NullMarker field used for null checking
+     arg_cnt++;
+   }
    const Type **field_array = fields(arg_cnt);
    switch (return_type->basic_type()) {
    case T_LONG:
      field_array[TypeFunc::Parms]   = TypeLong::LONG;
      field_array[TypeFunc::Parms+1] = Type::HALF;

*** 2063,10 ***
--- 2173,22 ---
    case T_DOUBLE:
      field_array[TypeFunc::Parms]   = Type::DOUBLE;
      field_array[TypeFunc::Parms+1] = Type::HALF;
      break;
    case T_OBJECT:
+     if (return_type->is_inlinetype() && ret_vt_fields) {
+       uint pos = TypeFunc::Parms;
+       field_array[pos++] = get_const_type(return_type); // Oop might be null when returning as fields
+       collect_inline_fields(return_type->as_inline_klass(), field_array, pos);
+       // InlineTypeNode::NullMarker field used for null checking
+       field_array[pos++] = get_const_basic_type(T_BOOLEAN);
+       assert(pos == (TypeFunc::Parms + arg_cnt), "out of bounds");
+       break;
+     } else {
+       field_array[TypeFunc::Parms] = get_const_type(return_type, interface_handling)->join_speculative(TypePtr::BOTTOM);
+     }
+     break;
    case T_ARRAY:
    case T_BOOLEAN:
    case T_CHAR:
    case T_FLOAT:
    case T_BYTE:

*** 2081,38 ***
    }
    return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
  }
  
  // Make a TypeTuple from the domain of a method signature
! const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig, InterfaceHandling interface_handling) {
!   uint arg_cnt = sig->size();
  
    uint pos = TypeFunc::Parms;
!   const Type **field_array;
!   if (recv != nullptr) {
!     arg_cnt++;
!     field_array = fields(arg_cnt);
!     // Use get_const_type here because it respects UseUniqueSubclasses:
!     field_array[pos++] = get_const_type(recv, interface_handling)->join_speculative(TypePtr::NOTNULL);
!   } else {
!     field_array = fields(arg_cnt);
    }
  
    int i = 0;
    while (pos < TypeFunc::Parms + arg_cnt) {
      ciType* type = sig->type_at(i);
  
!     switch (type->basic_type()) {
      case T_LONG:
        field_array[pos++] = TypeLong::LONG;
        field_array[pos++] = Type::HALF;
        break;
      case T_DOUBLE:
        field_array[pos++] = Type::DOUBLE;
        field_array[pos++] = Type::HALF;
        break;
      case T_OBJECT:
      case T_ARRAY:
      case T_FLOAT:
      case T_INT:
        field_array[pos++] = get_const_type(type, interface_handling);
        break;
--- 2203,55 ---
    }
    return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
  }
  
  // Make a TypeTuple from the domain of a method signature
! const TypeTuple *TypeTuple::make_domain(ciMethod* method, InterfaceHandling interface_handling, bool vt_fields_as_args) {
!   ciSignature* sig = method->signature();
+   uint arg_cnt = sig->size() + (method->is_static() ? 0 : 1);
+   if (vt_fields_as_args) {
+     arg_cnt = 0;
+     assert(method->get_sig_cc() != nullptr, "Should have scalarized signature");
+     for (ExtendedSignature sig_cc = ExtendedSignature(method->get_sig_cc(), SigEntryFilter()); !sig_cc.at_end(); ++sig_cc) {
+       arg_cnt += type2size[(*sig_cc)._bt];
+     }
+   }
  
    uint pos = TypeFunc::Parms;
!   const Type** field_array = fields(arg_cnt);
!   if (!method->is_static()) {
!     ciInstanceKlass* recv = method->holder();
!     if (vt_fields_as_args && recv->is_inlinetype() && recv->as_inline_klass()->can_be_passed_as_fields() && method->is_scalarized_arg(0)) {
!       collect_inline_fields(recv->as_inline_klass(), field_array, pos);
!     } else {
!       field_array[pos++] = get_const_type(recv, interface_handling)->join_speculative(TypePtr::NOTNULL);
!     }
    }
  
    int i = 0;
    while (pos < TypeFunc::Parms + arg_cnt) {
      ciType* type = sig->type_at(i);
+     BasicType bt = type->basic_type();
  
!     switch (bt) {
      case T_LONG:
        field_array[pos++] = TypeLong::LONG;
        field_array[pos++] = Type::HALF;
        break;
      case T_DOUBLE:
        field_array[pos++] = Type::DOUBLE;
        field_array[pos++] = Type::HALF;
        break;
      case T_OBJECT:
+       if (type->is_inlinetype() && vt_fields_as_args && method->is_scalarized_arg(i + (method->is_static() ? 0 : 1))) {
+         // InlineTypeNode::NullMarker field used for null checking
+         field_array[pos++] = get_const_basic_type(T_BOOLEAN);
+         collect_inline_fields(type->as_inline_klass(), field_array, pos);
+       } else {
+         field_array[pos++] = get_const_type(type, interface_handling);
+       }
+       break;
      case T_ARRAY:
      case T_FLOAT:
      case T_INT:
        field_array[pos++] = get_const_type(type, interface_handling);
        break;

*** 2125,10 ***
--- 2264,11 ---
      default:
        ShouldNotReachHere();
      }
      i++;
    }
+   assert(pos == TypeFunc::Parms + arg_cnt, "wrong number of arguments");
  
    return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
  }
  
  const TypeTuple *TypeTuple::make( uint cnt, const Type **fields ) {

*** 2259,16 ***
    else
      return size;
  }
  
  //------------------------------make-------------------------------------------
! const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
    if (UseCompressedOops && elem->isa_oopptr()) {
      elem = elem->make_narrowoop();
    }
    size = normalize_array_size(size);
!   return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.
  const Type *TypeAry::xmeet( const Type *t ) const {
--- 2399,17 ---
    else
      return size;
  }
  
  //------------------------------make-------------------------------------------
! const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable,
+                              bool flat, bool not_flat, bool not_null_free, bool atomic) {
    if (UseCompressedOops && elem->isa_oopptr()) {
      elem = elem->make_narrowoop();
    }
    size = normalize_array_size(size);
!   return (TypeAry*)(new TypeAry(elem, size, stable, flat, not_flat, not_null_free, atomic))->hashcons();
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.
  const Type *TypeAry::xmeet( const Type *t ) const {

*** 2291,11 ***
      if (isize == nullptr) {
        assert(size == Type::TOP || size == Type::BOTTOM, "");
        return size;
      }
      return TypeAry::make(_elem->meet_speculative(a->_elem),
!                          isize, _stable && a->_stable);
    }
    case Top:
      break;
    }
    return this;                  // Return the double constant
--- 2432,15 ---
      if (isize == nullptr) {
        assert(size == Type::TOP || size == Type::BOTTOM, "");
        return size;
      }
      return TypeAry::make(_elem->meet_speculative(a->_elem),
!                          isize, _stable && a->_stable,
+                          _flat && a->_flat,
+                          _not_flat && a->_not_flat,
+                          _not_null_free && a->_not_null_free,
+                          _atomic && a->_atomic);
    }
    case Top:
      break;
    }
    return this;                  // Return the double constant

*** 2304,40 ***
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type *TypeAry::xdual() const {
    const TypeInt* size_dual = _size->dual()->is_int();
    size_dual = normalize_array_size(size_dual);
!   return new TypeAry(_elem->dual(), size_dual, !_stable);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAry::eq( const Type *t ) const {
    const TypeAry *a = (const TypeAry*)t;
    return _elem == a->_elem &&
      _stable == a->_stable &&
!     _size == a->_size;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAry::hash(void) const {
!   return (uint)(uintptr_t)_elem + (uint)(uintptr_t)_size + (uint)(_stable ? 43 : 0);
  }
  
  /**
   * Return same type without a speculative part in the element
   */
  const TypeAry* TypeAry::remove_speculative() const {
!   return make(_elem->remove_speculative(), _size, _stable);
  }
  
  /**
   * Return same type with cleaned up speculative part of element
   */
  const Type* TypeAry::cleanup_speculative() const {
!   return make(_elem->cleanup_speculative(), _size, _stable);
  }
  
  /**
   * Return same type but with a different inline depth (used for speculation)
   *
--- 2449,46 ---
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type *TypeAry::xdual() const {
    const TypeInt* size_dual = _size->dual()->is_int();
    size_dual = normalize_array_size(size_dual);
!   return new TypeAry(_elem->dual(), size_dual, !_stable, !_flat, !_not_flat, !_not_null_free, !_atomic);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAry::eq( const Type *t ) const {
    const TypeAry *a = (const TypeAry*)t;
    return _elem == a->_elem &&
      _stable == a->_stable &&
!     _size == a->_size &&
+     _flat == a->_flat &&
+     _not_flat == a->_not_flat &&
+     _not_null_free == a->_not_null_free &&
+     _atomic == a->_atomic;
+ 
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAry::hash(void) const {
!   return (uint)(uintptr_t)_elem + (uint)(uintptr_t)_size + (uint)(_stable ? 43 : 0) +
+       (uint)(_flat ? 44 : 0) + (uint)(_not_flat ? 45 : 0) + (uint)(_not_null_free ? 46 : 0) + (uint)(_atomic ? 47 : 0);
  }
  
  /**
   * Return same type without a speculative part in the element
   */
  const TypeAry* TypeAry::remove_speculative() const {
!   return make(_elem->remove_speculative(), _size, _stable, _flat, _not_flat, _not_null_free, _atomic);
  }
  
  /**
   * Return same type with cleaned up speculative part of element
   */
  const Type* TypeAry::cleanup_speculative() const {
!   return make(_elem->cleanup_speculative(), _size, _stable, _flat, _not_flat, _not_null_free, _atomic);
  }
  
  /**
   * Return same type but with a different inline depth (used for speculation)
   *

*** 2352,10 ***
--- 2503,16 ---
  
  //------------------------------dump2------------------------------------------
  #ifndef PRODUCT
  void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
    if (_stable)  st->print("stable:");
+   if (_flat) st->print("flat:");
+   if (Verbose) {
+     if (_not_flat) st->print("not flat:");
+     if (_not_null_free) st->print("not null free:");
+   }
+   if (_atomic) st->print("atomic:");
    _elem->dump2(d, depth, st);
    st->print("[");
    _size->dump2(d, depth, st);
    st->print("]");
  }

*** 2391,12 ***
    const TypeInstPtr* tinst;
    if (_elem->isa_narrowoop())
      tinst = _elem->make_ptr()->isa_instptr();
    else
      tinst = _elem->isa_instptr();
!   if (tinst)
!     return tinst->instance_klass()->is_final();
    const TypeAryPtr*  tap;
    if (_elem->isa_narrowoop())
      tap = _elem->make_ptr()->isa_aryptr();
    else
      tap = _elem->isa_aryptr();
--- 2548,23 ---
    const TypeInstPtr* tinst;
    if (_elem->isa_narrowoop())
      tinst = _elem->make_ptr()->isa_instptr();
    else
      tinst = _elem->isa_instptr();
!   if (tinst) {
!     if (tinst->instance_klass()->is_final()) {
+       // Even though MyValue is final, [LMyValue is only exact if the array
+       // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue.
+       // TODO 8350865 If we know that the array can't be null-free, it's allowed to be exact, right?
+       // If so, we should add '&& !_not_null_free'
+       if (tinst->is_inlinetypeptr() && (tinst->ptr() != TypePtr::NotNull)) {
+         return false;
+       }
+       return true;
+     }
+     return false;
+   }
    const TypeAryPtr*  tap;
    if (_elem->isa_narrowoop())
      tap = _elem->make_ptr()->isa_aryptr();
    else
      tap = _elem->isa_aryptr();

*** 2567,11 ***
    { /* NotNull */ NotNull,   NotNull,   NotNull,  BotPTR, NotNull, BotPTR,},
    { /* BotPTR  */ BotPTR,    BotPTR,    BotPTR,   BotPTR, BotPTR,  BotPTR,}
  };
  
  //------------------------------make-------------------------------------------
! const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) {
    return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypePtr* TypePtr::cast_to_ptr_type(PTR ptr) const {
--- 2735,11 ---
    { /* NotNull */ NotNull,   NotNull,   NotNull,  BotPTR, NotNull, BotPTR,},
    { /* BotPTR  */ BotPTR,    BotPTR,    BotPTR,   BotPTR, BotPTR,  BotPTR,}
  };
  
  //------------------------------make-------------------------------------------
! const TypePtr* TypePtr::make(TYPES t, enum PTR ptr, Offset offset, const TypePtr* speculative, int inline_depth) {
    return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypePtr* TypePtr::cast_to_ptr_type(PTR ptr) const {

*** 2581,11 ***
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypePtr::get_con() const {
    assert( _ptr == Null, "" );
!   return _offset;
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.
  const Type *TypePtr::xmeet(const Type *t) const {
--- 2749,11 ---
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypePtr::get_con() const {
    assert( _ptr == Null, "" );
!   return offset();
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.
  const Type *TypePtr::xmeet(const Type *t) const {

*** 2655,71 ***
    }
    return this;
  }
  
  //------------------------------meet_offset------------------------------------
! int TypePtr::meet_offset( int offset ) const {
!   // Either is 'TOP' offset?  Return the other offset!
-   if( _offset == OffsetTop ) return offset;
-   if( offset == OffsetTop ) return _offset;
-   // If either is different, return 'BOTTOM' offset
-   if( _offset != offset ) return OffsetBot;
-   return _offset;
  }
  
  //------------------------------dual_offset------------------------------------
! int TypePtr::dual_offset( ) const {
!   if( _offset == OffsetTop ) return OffsetBot;// Map 'TOP' into 'BOTTOM'
-   if( _offset == OffsetBot ) return OffsetTop;// Map 'BOTTOM' into 'TOP'
-   return _offset;               // Map everything else into self
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = {
    BotPTR, NotNull, Constant, Null, AnyNull, TopPTR
  };
  const Type *TypePtr::xdual() const {
    return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth());
  }
  
  //------------------------------xadd_offset------------------------------------
! int TypePtr::xadd_offset( intptr_t offset ) const {
!   // Adding to 'TOP' offset?  Return 'TOP'!
-   if( _offset == OffsetTop || offset == OffsetTop ) return OffsetTop;
-   // Adding to 'BOTTOM' offset?  Return 'BOTTOM'!
-   if( _offset == OffsetBot || offset == OffsetBot ) return OffsetBot;
-   // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'!
-   offset += (intptr_t)_offset;
-   if (offset != (int)offset || offset == OffsetTop) return OffsetBot;
- 
-   // assert( _offset >= 0 && _offset+offset >= 0, "" );
-   // It is possible to construct a negative offset during PhaseCCP
- 
-   return (int)offset;        // Sum valid offsets
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr *TypePtr::add_offset( intptr_t offset ) const {
    return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth);
  }
  
  const TypePtr *TypePtr::with_offset(intptr_t offset) const {
!   return make(AnyPtr, _ptr, offset, _speculative, _inline_depth);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypePtr::eq( const Type *t ) const {
    const TypePtr *a = (const TypePtr*)t;
!   return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypePtr::hash(void) const {
!   return (uint)_ptr + (uint)_offset + (uint)hash_speculative() + (uint)_inline_depth;
  }
  
  /**
   * Return same type without a speculative part
   */
--- 2823,65 ---
    }
    return this;
  }
  
  //------------------------------meet_offset------------------------------------
! Type::Offset TypePtr::meet_offset(int offset) const {
!   return _offset.meet(Offset(offset));
  }
  
  //------------------------------dual_offset------------------------------------
! Type::Offset TypePtr::dual_offset() const {
!   return _offset.dual();
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = {
    BotPTR, NotNull, Constant, Null, AnyNull, TopPTR
  };
+ 
+ const TypePtr::FlatInArray TypePtr::flat_in_array_dual[Uninitialized] = {
+   /* TopFlat   -> */ MaybeFlat,
+   /* Flat      -> */ NotFlat,
+   /* NotFlat   -> */ Flat,
+   /* MaybeFlat -> */ TopFlat
+ };
+ 
+ const char* const TypePtr::flat_in_array_msg[Uninitialized] = {
+   "TOP flat in array", "flat in array", "not flat in array", "maybe flat in array"
+ };
+ 
  const Type *TypePtr::xdual() const {
    return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth());
  }
  
  //------------------------------xadd_offset------------------------------------
! Type::Offset TypePtr::xadd_offset(intptr_t offset) const {
!   return _offset.add(offset);
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr *TypePtr::add_offset( intptr_t offset ) const {
    return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth);
  }
  
  const TypePtr *TypePtr::with_offset(intptr_t offset) const {
!   return make(AnyPtr, _ptr, Offset(offset), _speculative, _inline_depth);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypePtr::eq( const Type *t ) const {
    const TypePtr *a = (const TypePtr*)t;
!   return _ptr == a->ptr() && _offset == a->_offset && eq_speculative(a) && _inline_depth == a->_inline_depth;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypePtr::hash(void) const {
!   return (uint)_ptr + (uint)offset() + (uint)hash_speculative() + (uint)_inline_depth;
  }
  
  /**
   * Return same type without a speculative part
   */

*** 2972,10 ***
--- 3134,43 ---
      return false;
    }
    return true;
  }
  
+ TypePtr::FlatInArray TypePtr::compute_flat_in_array(ciInstanceKlass* instance_klass, bool is_exact) {
+   if (!instance_klass->can_be_inline_klass(is_exact)) {
+     // Definitely not a value class and thus never flat in an array.
+     return NotFlat;
+   }
+   if (instance_klass->is_inlinetype() && instance_klass->as_inline_klass()->is_always_flat_in_array()) {
+     return Flat;
+   }
+   // We don't know.
+   return MaybeFlat;
+ }
+ 
+ // Compute flat in array property if we don't know anything about it (i.e. old_flat_in_array == MaybeFlat).
+ TypePtr::FlatInArray TypePtr::compute_flat_in_array_if_unknown(ciInstanceKlass* instance_klass, bool is_exact,
+   FlatInArray old_flat_in_array) const {
+   switch (old_flat_in_array) {
+     case Flat:
+       assert(can_be_inline_type(), "only value objects can be flat in array");
+       assert(!instance_klass->is_inlinetype() || instance_klass->as_inline_klass()->is_always_flat_in_array(),
+              "a value object is only marked flat in array if it's proven to be always flat in array");
+       break;
+     case NotFlat:
+       assert(!instance_klass->maybe_flat_in_array(), "cannot be flat");
+       break;
+     case MaybeFlat:
+       return compute_flat_in_array(instance_klass, is_exact);
+       break;
+     default:
+       break;
+   }
+   return old_flat_in_array;
+ }
+ 
  //------------------------------dump2------------------------------------------
  const char *const TypePtr::ptr_msg[TypePtr::lastPTR] = {
    "TopPTR","AnyNull","Constant","null","NotNull","BotPTR"
  };
  

*** 2986,17 ***
    dump_inline_depth(st);
    dump_speculative(st);
  }
  
  void TypePtr::dump_offset(outputStream* st) const {
!   if (_offset == OffsetBot) {
-     st->print("+bot");
-   } else if (_offset == OffsetTop) {
-     st->print("+top");
-   } else {
-     st->print("+%d", _offset);
-   }
  }
  
  /**
   *dump the speculative part of the type
   */
--- 3181,11 ---
    dump_inline_depth(st);
    dump_speculative(st);
  }
  
  void TypePtr::dump_offset(outputStream* st) const {
!   _offset.dump2(st);
  }
  
  /**
   *dump the speculative part of the type
   */

*** 3018,22 ***
      } else {
        st->print(" (inline_depth=%d)", _inline_depth);
      }
    }
  }
  #endif
  
  //------------------------------singleton--------------------------------------
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypePtr::singleton(void) const {
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (_offset != OffsetBot) && !below_centerline(_ptr);
  }
  
  bool TypePtr::empty(void) const {
!   return (_offset == OffsetTop) || above_centerline(_ptr);
  }
  
  //=============================================================================
  // Convenience common pre-built types.
  const TypeRawPtr *TypeRawPtr::BOTTOM;
--- 3207,38 ---
      } else {
        st->print(" (inline_depth=%d)", _inline_depth);
      }
    }
  }
+ 
+ void TypePtr::dump_flat_in_array(FlatInArray flat_in_array, outputStream* st) {
+   switch (flat_in_array) {
+     case MaybeFlat:
+     case NotFlat:
+       if (!Verbose) {
+         break;
+       }
+     case TopFlat:
+     case Flat:
+       st->print(" (%s)", flat_in_array_msg[flat_in_array]);
+       break;
+     default:
+       ShouldNotReachHere();
+   }
+ }
  #endif
  
  //------------------------------singleton--------------------------------------
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypePtr::singleton(void) const {
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (_offset != Offset::bottom) && !below_centerline(_ptr);
  }
  
  bool TypePtr::empty(void) const {
!   return (_offset == Offset::top) || above_centerline(_ptr);
  }
  
  //=============================================================================
  // Convenience common pre-built types.
  const TypeRawPtr *TypeRawPtr::BOTTOM;

*** 3437,73 ***
  
    return !TypeAryPtr::_array_interfaces->contains(this);
  }
  
  //------------------------------TypeOopPtr-------------------------------------
! TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset,
                         int instance_id, const TypePtr* speculative, int inline_depth)
    : TypePtr(t, ptr, offset, speculative, inline_depth),
      _const_oop(o), _klass(k),
      _interfaces(interfaces),
      _klass_is_exact(xk),
      _is_ptr_to_narrowoop(false),
      _is_ptr_to_narrowklass(false),
      _is_ptr_to_boxed_value(false),
      _instance_id(instance_id) {
  #ifdef ASSERT
    if (klass() != nullptr && klass()->is_loaded()) {
      interfaces->verify_is_loaded();
    }
  #endif
    if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
!       (offset > 0) && xk && (k != nullptr) && k->is_instance_klass()) {
!     _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
    }
  #ifdef _LP64
!   if (_offset > 0 || _offset == Type::OffsetTop || _offset == Type::OffsetBot) {
!     if (_offset == oopDesc::klass_offset_in_bytes()) {
        _is_ptr_to_narrowklass = UseCompressedClassPointers;
      } else if (klass() == nullptr) {
        // Array with unknown body type
        assert(this->isa_aryptr(), "only arrays without klass");
        _is_ptr_to_narrowoop = UseCompressedOops;
!     } else if (this->isa_aryptr()) {
!       _is_ptr_to_narrowoop = (UseCompressedOops && klass()->is_obj_array_klass() &&
!                              _offset != arrayOopDesc::length_offset_in_bytes());
      } else if (klass()->is_instance_klass()) {
-       ciInstanceKlass* ik = klass()->as_instance_klass();
        if (this->isa_klassptr()) {
          // Perm objects don't use compressed references
!       } else if (_offset == OffsetBot || _offset == OffsetTop) {
          // unsafe access
          _is_ptr_to_narrowoop = UseCompressedOops;
        } else {
          assert(this->isa_instptr(), "must be an instance ptr.");
- 
          if (klass() == ciEnv::current()->Class_klass() &&
!             (_offset == java_lang_Class::klass_offset() ||
!              _offset == java_lang_Class::array_klass_offset())) {
            // Special hidden fields from the Class.
            assert(this->isa_instptr(), "must be an instance ptr.");
            _is_ptr_to_narrowoop = false;
          } else if (klass() == ciEnv::current()->Class_klass() &&
!                    _offset >= InstanceMirrorKlass::offset_of_static_fields()) {
            // Static fields
            BasicType basic_elem_type = T_ILLEGAL;
            if (const_oop() != nullptr) {
              ciInstanceKlass* k = const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass();
!             basic_elem_type = k->get_field_type_by_offset(_offset, true);
            }
            if (basic_elem_type != T_ILLEGAL) {
              _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
            } else {
              // unsafe access
              _is_ptr_to_narrowoop = UseCompressedOops;
            }
          } else {
            // Instance fields which contains a compressed oop references.
!           BasicType basic_elem_type = ik->get_field_type_by_offset(_offset, false);
            if (basic_elem_type != T_ILLEGAL) {
              _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
            } else if (klass()->equals(ciEnv::current()->Object_klass())) {
              // Compile::find_alias_type() cast exactness on all types to verify
              // that it does not affect alias type.
--- 3642,97 ---
  
    return !TypeAryPtr::_array_interfaces->contains(this);
  }
  
  //------------------------------TypeOopPtr-------------------------------------
! TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, Offset offset, Offset field_offset,
                         int instance_id, const TypePtr* speculative, int inline_depth)
    : TypePtr(t, ptr, offset, speculative, inline_depth),
      _const_oop(o), _klass(k),
      _interfaces(interfaces),
      _klass_is_exact(xk),
      _is_ptr_to_narrowoop(false),
      _is_ptr_to_narrowklass(false),
      _is_ptr_to_boxed_value(false),
+     _is_ptr_to_strict_final_field(false),
      _instance_id(instance_id) {
  #ifdef ASSERT
    if (klass() != nullptr && klass()->is_loaded()) {
      interfaces->verify_is_loaded();
    }
  #endif
    if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
!       (offset.get() > 0) && xk && (k != nullptr) && k->is_instance_klass()) {
!     _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset.get());
+     _is_ptr_to_strict_final_field = _is_ptr_to_boxed_value;
    }
+ 
+   if (klass() != nullptr && klass()->is_instance_klass() && klass()->is_loaded() &&
+       this->offset() != Type::OffsetBot && this->offset() != Type::OffsetTop) {
+     ciField* field = klass()->as_instance_klass()->get_field_by_offset(this->offset(), false);
+     if (field != nullptr && field->is_strict() && field->is_final()) {
+       _is_ptr_to_strict_final_field = true;
+     }
+   }
+ 
  #ifdef _LP64
!   if (this->offset() > 0 || this->offset() == Type::OffsetTop || this->offset() == Type::OffsetBot) {
!     if (this->offset() == oopDesc::klass_offset_in_bytes()) {
        _is_ptr_to_narrowklass = UseCompressedClassPointers;
      } else if (klass() == nullptr) {
        // Array with unknown body type
        assert(this->isa_aryptr(), "only arrays without klass");
        _is_ptr_to_narrowoop = UseCompressedOops;
!     } else if (UseCompressedOops && this->isa_aryptr() && this->offset() != arrayOopDesc::length_offset_in_bytes()) {
!       if (klass()->is_obj_array_klass()) {
!         _is_ptr_to_narrowoop = true;
+       } else if (klass()->is_flat_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) {
+         // Check if the field of the inline type array element contains oops
+         ciInlineKlass* vk = klass()->as_flat_array_klass()->element_klass()->as_inline_klass();
+         int foffset = field_offset.get() + vk->payload_offset();
+         BasicType field_bt;
+         ciField* field = vk->get_field_by_offset(foffset, false);
+         if (field != nullptr) {
+           field_bt = field->layout_type();
+         } else {
+           assert(field_offset.get() == vk->null_marker_offset_in_payload(), "no field or null marker of %s at offset %d", vk->name()->as_utf8(), foffset);
+           field_bt = T_BOOLEAN;
+         }
+         _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(field_bt);
+       }
      } else if (klass()->is_instance_klass()) {
        if (this->isa_klassptr()) {
          // Perm objects don't use compressed references
!       } else if (_offset == Offset::bottom || _offset == Offset::top) {
          // unsafe access
          _is_ptr_to_narrowoop = UseCompressedOops;
        } else {
          assert(this->isa_instptr(), "must be an instance ptr.");
          if (klass() == ciEnv::current()->Class_klass() &&
!             (this->offset() == java_lang_Class::klass_offset() ||
!              this->offset() == java_lang_Class::array_klass_offset())) {
            // Special hidden fields from the Class.
            assert(this->isa_instptr(), "must be an instance ptr.");
            _is_ptr_to_narrowoop = false;
          } else if (klass() == ciEnv::current()->Class_klass() &&
!                    this->offset() >= InstanceMirrorKlass::offset_of_static_fields()) {
            // Static fields
            BasicType basic_elem_type = T_ILLEGAL;
            if (const_oop() != nullptr) {
              ciInstanceKlass* k = const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass();
!             basic_elem_type = k->get_field_type_by_offset(this->offset(), true);
            }
            if (basic_elem_type != T_ILLEGAL) {
              _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
            } else {
              // unsafe access
              _is_ptr_to_narrowoop = UseCompressedOops;
            }
          } else {
            // Instance fields which contains a compressed oop references.
!           ciInstanceKlass* ik = klass()->as_instance_klass();
+           BasicType basic_elem_type = ik->get_field_type_by_offset(this->offset(), false);
            if (basic_elem_type != T_ILLEGAL) {
              _is_ptr_to_narrowoop = UseCompressedOops && ::is_reference_type(basic_elem_type);
            } else if (klass()->equals(ciEnv::current()->Object_klass())) {
              // Compile::find_alias_type() cast exactness on all types to verify
              // that it does not affect alias type.

*** 3514,22 ***
            }
          }
        }
      }
    }
! #endif
  }
  
  //------------------------------make-------------------------------------------
! const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id,
!                                      const TypePtr* speculative, int inline_depth) {
    assert(ptr != Constant, "no constant generic pointers");
    ciKlass*  k = Compile::current()->env()->Object_klass();
    bool      xk = false;
    ciObject* o = nullptr;
    const TypeInterfaces* interfaces = TypeInterfaces::make();
!   return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, interfaces, xk, o, offset, instance_id, speculative, inline_depth))->hashcons();
  }
  
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeOopPtr* TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
--- 3743,22 ---
            }
          }
        }
      }
    }
! #endif // _LP64
  }
  
  //------------------------------make-------------------------------------------
! const TypeOopPtr *TypeOopPtr::make(PTR ptr, Offset offset, int instance_id,
!                                    const TypePtr* speculative, int inline_depth) {
    assert(ptr != Constant, "no constant generic pointers");
    ciKlass*  k = Compile::current()->env()->Object_klass();
    bool      xk = false;
    ciObject* o = nullptr;
    const TypeInterfaces* interfaces = TypeInterfaces::make();
!   return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, interfaces, xk, o, offset, Offset::bottom, instance_id, speculative, inline_depth))->hashcons();
  }
  
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeOopPtr* TypeOopPtr::cast_to_ptr_type(PTR ptr) const {

*** 3550,11 ***
    // There is no such thing as an exact general oop.
    // Return self unchanged.
    return this;
  }
  
- 
  //------------------------------as_klass_type----------------------------------
  // Return the klass type corresponding to this instance or array type.
  // It is the type that is loaded from an object of this type.
  const TypeKlassPtr* TypeOopPtr::as_klass_type(bool try_for_exact) const {
    ShouldNotReachHere();
--- 3779,10 ---

*** 3599,11 ***
      return TypePtr::BOTTOM;     // Oop meet raw is not well defined
  
    case AnyPtr: {
      // Found an AnyPtr type vs self-OopPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {
      case Null:
--- 3827,11 ---
      return TypePtr::BOTTOM;     // Oop meet raw is not well defined
  
    case AnyPtr: {
      // Found an AnyPtr type vs self-OopPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {
      case Null:

*** 3641,25 ***
  //------------------------------xdual------------------------------------------
  // Dual of a pure heap pointer.  No relevant klass or oop information.
  const Type *TypeOopPtr::xdual() const {
    assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
    assert(const_oop() == nullptr,             "no constants here");
!   return new TypeOopPtr(_base, dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
  }
  
  //--------------------------make_from_klass_common-----------------------------
  // Computes the element-type given a klass.
! const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling) {
!   if (klass->is_instance_klass()) {
      Compile* C = Compile::current();
      Dependencies* deps = C->dependencies();
      assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
      // Element is an instance
      bool klass_is_exact = false;
      if (klass->is_loaded()) {
        // Try to set klass_is_exact.
-       ciInstanceKlass* ik = klass->as_instance_klass();
        klass_is_exact = ik->is_final();
        if (!klass_is_exact && klass_change
            && deps != nullptr && UseUniqueSubclasses) {
          ciInstanceKlass* sub = ik->unique_concrete_subklass();
          if (sub != nullptr) {
--- 3869,25 ---
  //------------------------------xdual------------------------------------------
  // Dual of a pure heap pointer.  No relevant klass or oop information.
  const Type *TypeOopPtr::xdual() const {
    assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
    assert(const_oop() == nullptr,             "no constants here");
!   return new TypeOopPtr(_base, dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), Offset::bottom, dual_instance_id(), dual_speculative(), dual_inline_depth());
  }
  
  //--------------------------make_from_klass_common-----------------------------
  // Computes the element-type given a klass.
! const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact, InterfaceHandling interface_handling) {
!   if (klass->is_instance_klass() || klass->is_inlinetype()) {
      Compile* C = Compile::current();
      Dependencies* deps = C->dependencies();
      assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
      // Element is an instance
      bool klass_is_exact = false;
+     ciInstanceKlass* ik = klass->as_instance_klass();
      if (klass->is_loaded()) {
        // Try to set klass_is_exact.
        klass_is_exact = ik->is_final();
        if (!klass_is_exact && klass_change
            && deps != nullptr && UseUniqueSubclasses) {
          ciInstanceKlass* sub = ik->unique_concrete_subklass();
          if (sub != nullptr) {

*** 3673,30 ***
          // Add a dependence; if concrete subclass added we need to recompile
          deps->assert_leaf_type(ik);
          klass_is_exact = true;
        }
      }
      const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
!     return TypeInstPtr::make(TypePtr::BotPTR, klass, interfaces, klass_is_exact, nullptr, 0);
    } else if (klass->is_obj_array_klass()) {
!     // Element is an object array. Recursively call ourself.
!     ciKlass* eklass = klass->as_obj_array_klass()->element_klass();
!     const TypeOopPtr *etype = TypeOopPtr::make_from_klass_common(eklass, false, try_for_exact, interface_handling);
!     bool xk = etype->klass_is_exact();
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
      // We used to pass NotNull in here, asserting that the sub-arrays
      // are all not-null.  This is not true in generally, as code can
!     // slam nulls down in the subarrays.
!     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, nullptr, xk, 0);
      return arr;
    } else if (klass->is_type_array_klass()) {
      // Element is an typeArray
      const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
      // We used to pass NotNull in here, asserting that the array pointer
      // is not-null. That was not true in general.
!     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, 0);
      return arr;
    } else {
      ShouldNotReachHere();
      return nullptr;
    }
--- 3901,55 ---
          // Add a dependence; if concrete subclass added we need to recompile
          deps->assert_leaf_type(ik);
          klass_is_exact = true;
        }
      }
+     FlatInArray flat_in_array = compute_flat_in_array(ik, klass_is_exact);
      const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
!     return TypeInstPtr::make(TypePtr::BotPTR, klass, interfaces, klass_is_exact, nullptr, Offset(0), flat_in_array);
    } else if (klass->is_obj_array_klass()) {
!     // Element is an object or inline type array. Recursively call ourself.
!     const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ false, try_for_exact, interface_handling);
!     bool xk = klass->is_loaded() && klass->as_obj_array_klass()->is_refined();
!     // Determine null-free/flat properties
!     const bool is_null_free = xk && klass->as_array_klass()->is_elem_null_free();
+     if (is_null_free) {
+       etype = etype->join_speculative(NOTNULL)->is_oopptr();
+     }
+     const TypeOopPtr* exact_etype = etype;
+     if (etype->can_be_inline_type()) {
+       // Use exact type if element can be an inline type
+       exact_etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ true, /* try_for_exact= */ true, interface_handling);
+     }
+     bool not_inline = !exact_etype->can_be_inline_type();
+     bool not_null_free = xk ? !is_null_free : not_inline;
+     bool not_flat = xk || !UseArrayFlattening || not_inline || (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->maybe_flat_in_array());
+     bool atomic = not_flat;
+     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ false, not_flat, not_null_free, atomic);
      // We used to pass NotNull in here, asserting that the sub-arrays
      // are all not-null.  This is not true in generally, as code can
!     // slam nullptrs down in the subarrays.
!     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, nullptr, xk, Offset(0));
      return arr;
    } else if (klass->is_type_array_klass()) {
      // Element is an typeArray
      const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS,
+                                         /* stable= */ false, /* flat= */ false, /* not_flat= */ true, /* not_null_free= */ true, true);
      // We used to pass NotNull in here, asserting that the array pointer
      // is not-null. That was not true in general.
!     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0));
+     return arr;
+   } else if (klass->is_flat_array_klass()) {
+     const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass(), trust_interfaces);
+     const bool is_null_free = klass->as_array_klass()->is_elem_null_free();
+     if (is_null_free) {
+       etype = etype->join_speculative(NOTNULL)->is_oopptr();
+     }
+     bool atomic = klass->as_array_klass()->is_elem_atomic();
+     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, /* stable= */ false, /* flat= */ true, /* not_flat= */ false, /* not_null_free= */ !is_null_free, atomic);
+     const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0));
      return arr;
    } else {
      ShouldNotReachHere();
      return nullptr;
    }

*** 3708,54 ***
    assert(!o->is_null_object(), "null object not yet handled here.");
  
    const bool make_constant = require_constant || o->should_be_constant();
  
    ciKlass* klass = o->klass();
!   if (klass->is_instance_klass()) {
!     // Element is an instance
      if (make_constant) {
        return TypeInstPtr::make(o);
      } else {
!       return TypeInstPtr::make(TypePtr::NotNull, klass, true, nullptr, 0);
      }
    } else if (klass->is_obj_array_klass()) {
      // Element is an object array. Recursively call ourself.
!     const TypeOopPtr *etype =
!       TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass(), trust_interfaces);
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
      // We used to pass NotNull in here, asserting that the sub-arrays
      // are all not-null.  This is not true in generally, as code can
      // slam nulls down in the subarrays.
      if (make_constant) {
!       return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
      } else {
!       return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
      }
    } else if (klass->is_type_array_klass()) {
      // Element is an typeArray
!     const Type* etype =
!       (Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
      // We used to pass NotNull in here, asserting that the array pointer
      // is not-null. That was not true in general.
      if (make_constant) {
!       return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
      } else {
!       return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
      }
    }
  
    fatal("unhandled object type");
    return nullptr;
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypeOopPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert( _offset >= 0, "" );
  
!   if (_offset != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't
--- 3961,77 ---
    assert(!o->is_null_object(), "null object not yet handled here.");
  
    const bool make_constant = require_constant || o->should_be_constant();
  
    ciKlass* klass = o->klass();
!   if (klass->is_instance_klass() || klass->is_inlinetype()) {
!     // Element is an instance or inline type
      if (make_constant) {
        return TypeInstPtr::make(o);
      } else {
!       return TypeInstPtr::make(TypePtr::NotNull, klass, true, nullptr, Offset(0));
      }
    } else if (klass->is_obj_array_klass()) {
      // Element is an object array. Recursively call ourself.
!     const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass(), trust_interfaces);
!     bool is_flat = o->as_array()->is_flat();
!     bool is_null_free = o->as_array()->is_null_free();
+     if (is_null_free) {
+       etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr();
+     }
+     bool is_atomic = o->as_array()->is_atomic();
+     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ false,
+                                         /* not_flat= */ !is_flat, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic);
      // We used to pass NotNull in here, asserting that the sub-arrays
      // are all not-null.  This is not true in generally, as code can
      // slam nulls down in the subarrays.
      if (make_constant) {
!       return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
      } else {
!       return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
      }
    } else if (klass->is_type_array_klass()) {
      // Element is an typeArray
!     const Type* etype = (Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
!     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ false,
!                                         /* not_flat= */ true, /* not_null_free= */ true, true);
      // We used to pass NotNull in here, asserting that the array pointer
      // is not-null. That was not true in general.
      if (make_constant) {
!       return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
+     } else {
+       return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
+     }
+   } else if (klass->is_flat_array_klass()) {
+     const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass(), trust_interfaces);
+     bool is_null_free = o->as_array()->is_null_free();
+     if (is_null_free) {
+       etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr();
+     }
+     bool is_atomic = o->as_array()->is_atomic();
+     const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()), /* stable= */ false, /* flat= */ true,
+                                         /* not_flat= */ false, /* not_null_free= */ !is_null_free, /* atomic= */ is_atomic);
+     // We used to pass NotNull in here, asserting that the sub-arrays
+     // are all not-null.  This is not true in generally, as code can
+     // slam nullptrs down in the subarrays.
+     if (make_constant) {
+       return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
      } else {
!       return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
      }
    }
  
    fatal("unhandled object type");
    return nullptr;
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypeOopPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert(offset() >= 0, "");
  
!   if (offset() != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't

*** 3837,20 ***
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeOopPtr::singleton(void) const {
    // detune optimizer to not generate constant oop + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (_offset == 0) && !below_centerline(_ptr);
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeOopPtr::add_offset(intptr_t offset) const {
    return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
  }
  
  const TypeOopPtr* TypeOopPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, offset, _instance_id, with_offset_speculative(offset), _inline_depth);
  }
  
  /**
   * Return same type without a speculative part
   */
--- 4113,20 ---
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeOopPtr::singleton(void) const {
    // detune optimizer to not generate constant oop + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (offset() == 0) && !below_centerline(_ptr);
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeOopPtr::add_offset(intptr_t offset) const {
    return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
  }
  
  const TypeOopPtr* TypeOopPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, Offset(offset), _instance_id, with_offset_speculative(offset), _inline_depth);
  }
  
  /**
   * Return same type without a speculative part
   */

*** 3959,13 ***
    }
    return _interfaces->exact_klass();
  }
  
  //------------------------------TypeInstPtr-------------------------------------
! TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int off,
!                          int instance_id, const TypePtr* speculative, int inline_depth)
!   : TypeOopPtr(InstPtr, ptr, k, interfaces, xk, o, off, instance_id, speculative, inline_depth) {
    assert(k == nullptr || !k->is_loaded() || !k->is_interface(), "no interface here");
    assert(k != nullptr &&
           (k->is_loaded() || o == nullptr),
           "cannot have constants with non-loaded klass");
  };
--- 4235,16 ---
    }
    return _interfaces->exact_klass();
  }
  
  //------------------------------TypeInstPtr-------------------------------------
! TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, Offset off,
!                          FlatInArray flat_in_array, int instance_id, const TypePtr* speculative, int inline_depth)
!   : TypeOopPtr(InstPtr, ptr, k, interfaces, xk, o, off, Offset::bottom, instance_id, speculative, inline_depth),
+     _flat_in_array(flat_in_array) {
+ 
+   assert(flat_in_array != Uninitialized, "must be set now");
    assert(k == nullptr || !k->is_loaded() || !k->is_interface(), "no interface here");
    assert(k != nullptr &&
           (k->is_loaded() || o == nullptr),
           "cannot have constants with non-loaded klass");
  };

*** 3974,11 ***
  const TypeInstPtr *TypeInstPtr::make(PTR ptr,
                                       ciKlass* k,
                                       const TypeInterfaces* interfaces,
                                       bool xk,
                                       ciObject* o,
!                                      int offset,
                                       int instance_id,
                                       const TypePtr* speculative,
                                       int inline_depth) {
    assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
    // Either const_oop() is null or else ptr is Constant
--- 4253,12 ---
  const TypeInstPtr *TypeInstPtr::make(PTR ptr,
                                       ciKlass* k,
                                       const TypeInterfaces* interfaces,
                                       bool xk,
                                       ciObject* o,
!                                      Offset offset,
+                                      FlatInArray flat_in_array,
                                       int instance_id,
                                       const TypePtr* speculative,
                                       int inline_depth) {
    assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
    // Either const_oop() is null or else ptr is Constant

*** 3986,23 ***
            "constant pointers must have a value supplied" );
    // Ptr is never Null
    assert( ptr != Null, "null pointers are not typed" );
  
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
    if (ptr == Constant) {
      // Note:  This case includes meta-object constants, such as methods.
      xk = true;
    } else if (k->is_loaded()) {
-     ciInstanceKlass* ik = k->as_instance_klass();
      if (!xk && ik->is_final())     xk = true;   // no inexact final klass
      assert(!ik->is_interface(), "no interface here");
      if (xk && ik->is_interface())  xk = false;  // no exact interface
    }
  
    // Now hash this baby
    TypeInstPtr *result =
!     (TypeInstPtr*)(new TypeInstPtr(ptr, k, interfaces, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons();
  
    return result;
  }
  
  const TypeInterfaces* TypePtr::interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling) {
--- 4266,26 ---
            "constant pointers must have a value supplied" );
    // Ptr is never Null
    assert( ptr != Null, "null pointers are not typed" );
  
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
+   ciInstanceKlass* ik = k->as_instance_klass();
    if (ptr == Constant) {
      // Note:  This case includes meta-object constants, such as methods.
      xk = true;
    } else if (k->is_loaded()) {
      if (!xk && ik->is_final())     xk = true;   // no inexact final klass
      assert(!ik->is_interface(), "no interface here");
      if (xk && ik->is_interface())  xk = false;  // no exact interface
    }
  
+   if (flat_in_array == Uninitialized) {
+     flat_in_array = compute_flat_in_array(ik, xk);
+   }
    // Now hash this baby
    TypeInstPtr *result =
!     (TypeInstPtr*)(new TypeInstPtr(ptr, k, interfaces, xk, o, offset, flat_in_array, instance_id, speculative, inline_depth))->hashcons();
  
    return result;
  }
  
  const TypeInterfaces* TypePtr::interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling) {

*** 4064,35 ***
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
    if( ptr == _ptr ) return this;
    // Reconstruct _sig info here since not a problem with later lazy
    // construction, _sig will show up on demand.
!   return make(ptr, klass(), _interfaces, klass_is_exact(), ptr == Constant ? const_oop() : nullptr, _offset, _instance_id, _speculative, _inline_depth);
  }
  
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
    if( klass_is_exact == _klass_is_exact ) return this;
    if (!_klass->is_loaded())  return this;
    ciInstanceKlass* ik = _klass->as_instance_klass();
    if( (ik->is_final() || _const_oop) )  return this;  // cannot clear xk
    assert(!ik->is_interface(), "no interface here");
!   return make(ptr(), klass(), _interfaces, klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth);
  }
  
  //-----------------------------cast_to_instance_id----------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_instance_id(int instance_id) const {
    if( instance_id == _instance_id ) return this;
!   return make(_ptr, klass(),  _interfaces, _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth);
  }
  
  //------------------------------xmeet_unloaded---------------------------------
  // Compute the MEET of two InstPtrs when at least one is unloaded.
  // Assume classes are different since called after check for same name/class-loader
  const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const {
!   int off = meet_offset(tinst->offset());
    PTR ptr = meet_ptr(tinst->ptr());
    int instance_id = meet_instance_id(tinst->instance_id());
    const TypePtr* speculative = xmeet_speculative(tinst);
    int depth = meet_inline_depth(tinst->inline_depth());
  
--- 4347,36 ---
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
    if( ptr == _ptr ) return this;
    // Reconstruct _sig info here since not a problem with later lazy
    // construction, _sig will show up on demand.
!   return make(ptr, klass(), _interfaces, klass_is_exact(), ptr == Constant ? const_oop() : nullptr, _offset, _flat_in_array, _instance_id, _speculative, _inline_depth);
  }
  
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
    if( klass_is_exact == _klass_is_exact ) return this;
    if (!_klass->is_loaded())  return this;
    ciInstanceKlass* ik = _klass->as_instance_klass();
    if( (ik->is_final() || _const_oop) )  return this;  // cannot clear xk
    assert(!ik->is_interface(), "no interface here");
!   FlatInArray flat_in_array = compute_flat_in_array(ik, klass_is_exact);
+   return make(ptr(), klass(), _interfaces, klass_is_exact, const_oop(), _offset, flat_in_array, _instance_id, _speculative, _inline_depth);
  }
  
  //-----------------------------cast_to_instance_id----------------------------
  const TypeInstPtr* TypeInstPtr::cast_to_instance_id(int instance_id) const {
    if( instance_id == _instance_id ) return this;
!   return make(_ptr, klass(), _interfaces, _klass_is_exact, const_oop(), _offset, _flat_in_array, instance_id, _speculative, _inline_depth);
  }
  
  //------------------------------xmeet_unloaded---------------------------------
  // Compute the MEET of two InstPtrs when at least one is unloaded.
  // Assume classes are different since called after check for same name/class-loader
  const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const {
!   Offset off = meet_offset(tinst->offset());
    PTR ptr = meet_ptr(tinst->ptr());
    int instance_id = meet_instance_id(tinst->instance_id());
    const TypePtr* speculative = xmeet_speculative(tinst);
    int depth = meet_inline_depth(tinst->inline_depth());
  

*** 4113,11 ***
      //  BOTTOM  | ........................Object-BOTTOM ..................|
      //
      assert(loaded->ptr() != TypePtr::Null, "insanity check");
      //
      if (loaded->ptr() == TypePtr::TopPTR)        { return unloaded->with_speculative(speculative); }
!     else if (loaded->ptr() == TypePtr::AnyNull)  { return make(ptr, unloaded->klass(), interfaces, false, nullptr, off, instance_id, speculative, depth); }
      else if (loaded->ptr() == TypePtr::BotPTR)   { return TypeInstPtr::BOTTOM->with_speculative(speculative); }
      else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
        if (unloaded->ptr() == TypePtr::BotPTR)    { return TypeInstPtr::BOTTOM->with_speculative(speculative);  }
        else                                       { return TypeInstPtr::NOTNULL->with_speculative(speculative); }
      }
--- 4397,15 ---
      //  BOTTOM  | ........................Object-BOTTOM ..................|
      //
      assert(loaded->ptr() != TypePtr::Null, "insanity check");
      //
      if (loaded->ptr() == TypePtr::TopPTR)        { return unloaded->with_speculative(speculative); }
!     else if (loaded->ptr() == TypePtr::AnyNull)  {
+       FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tinst->flat_in_array());
+       return make(ptr, unloaded->klass(), interfaces, false, nullptr, off, flat_in_array, instance_id,
+                   speculative, depth);
+     }
      else if (loaded->ptr() == TypePtr::BotPTR)   { return TypeInstPtr::BOTTOM->with_speculative(speculative); }
      else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
        if (unloaded->ptr() == TypePtr::BotPTR)    { return TypeInstPtr::BOTTOM->with_speculative(speculative);  }
        else                                       { return TypeInstPtr::NOTNULL->with_speculative(speculative); }
      }

*** 4177,20 ***
    }
  
    case OopPtr: {                // Meeting to OopPtrs
      // Found a OopPtr type vs self-InstPtr type
      const TypeOopPtr *tp = t->is_oopptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        const TypePtr* speculative = xmeet_speculative(tp);
        int depth = meet_inline_depth(tp->inline_depth());
        return make(ptr, klass(), _interfaces, klass_is_exact(),
!                   (ptr == Constant ? const_oop() : nullptr), offset, instance_id, speculative, depth);
      }
      case NotNull:
      case BotPTR: {
        int instance_id = meet_instance_id(tp->instance_id());
        const TypePtr* speculative = xmeet_speculative(tp);
--- 4465,20 ---
    }
  
    case OopPtr: {                // Meeting to OopPtrs
      // Found a OopPtr type vs self-InstPtr type
      const TypeOopPtr *tp = t->is_oopptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        const TypePtr* speculative = xmeet_speculative(tp);
        int depth = meet_inline_depth(tp->inline_depth());
        return make(ptr, klass(), _interfaces, klass_is_exact(),
!                   (ptr == Constant ? const_oop() : nullptr), offset, flat_in_array(), instance_id, speculative, depth);
      }
      case NotNull:
      case BotPTR: {
        int instance_id = meet_instance_id(tp->instance_id());
        const TypePtr* speculative = xmeet_speculative(tp);

*** 4202,11 ***
    }
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-InstPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int instance_id = meet_instance_id(InstanceTop);
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {
--- 4490,11 ---
    }
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-InstPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int instance_id = meet_instance_id(InstanceTop);
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {

*** 4214,11 ***
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
        // else fall through to AnyNull
      case TopPTR:
      case AnyNull: {
        return make(ptr, klass(), _interfaces, klass_is_exact(),
!                   (ptr == Constant ? const_oop() : nullptr), offset, instance_id, speculative, depth);
      }
      case NotNull:
      case BotPTR:
        return TypePtr::make(AnyPtr, ptr, offset, speculative,depth);
      default: typerr(t);
--- 4502,11 ---
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
        // else fall through to AnyNull
      case TopPTR:
      case AnyNull: {
        return make(ptr, klass(), _interfaces, klass_is_exact(),
!                   (ptr == Constant ? const_oop() : nullptr), offset, flat_in_array(), instance_id, speculative, depth);
      }
      case NotNull:
      case BotPTR:
        return TypePtr::make(AnyPtr, ptr, offset, speculative,depth);
      default: typerr(t);

*** 4242,11 ***
    */
  
    case InstPtr: {                // Meeting 2 Oops?
      // Found an InstPtr sub-type vs self-InstPtr type
      const TypeInstPtr *tinst = t->is_instptr();
!     int off = meet_offset(tinst->offset());
      PTR ptr = meet_ptr(tinst->ptr());
      int instance_id = meet_instance_id(tinst->instance_id());
      const TypePtr* speculative = xmeet_speculative(tinst);
      int depth = meet_inline_depth(tinst->inline_depth());
      const TypeInterfaces* interfaces = meet_interfaces(tinst);
--- 4530,11 ---
    */
  
    case InstPtr: {                // Meeting 2 Oops?
      // Found an InstPtr sub-type vs self-InstPtr type
      const TypeInstPtr *tinst = t->is_instptr();
!     Offset off = meet_offset(tinst->offset());
      PTR ptr = meet_ptr(tinst->ptr());
      int instance_id = meet_instance_id(tinst->instance_id());
      const TypePtr* speculative = xmeet_speculative(tinst);
      int depth = meet_inline_depth(tinst->inline_depth());
      const TypeInterfaces* interfaces = meet_interfaces(tinst);

*** 4275,10 ***
--- 4563,11 ---
          tty->cr();
        }
  #endif
        res = unloaded_meet;
      } else {
+       FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tinst->flat_in_array());
        if (kind == NOT_SUBTYPE && instance_id > 0) {
          instance_id = InstanceBot;
        } else if (kind == LCA) {
          instance_id = InstanceBot;
        }

*** 4296,11 ***
            assert(!this_klass->is_interface(), "");
            o = this_oop;
          } else
            ptr = NotNull;
        }
!       res = make(ptr, res_klass, interfaces, res_xk, o, off, instance_id, speculative, depth);
      }
  
      return res;
  
    } // End of case InstPtr
--- 4585,11 ---
            assert(!this_klass->is_interface(), "");
            o = this_oop;
          } else
            ptr = NotNull;
        }
!       res = make(ptr, res_klass, interfaces, res_xk, o, off, flat_in_array, instance_id, speculative, depth);
      }
  
      return res;
  
    } // End of case InstPtr

*** 4311,10 ***
--- 4600,11 ---
  
  template<class T> TypePtr::MeetResult TypePtr::meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type, const T* other_type,
                                                              ciKlass*& res_klass, bool& res_xk) {
    ciKlass* this_klass = this_type->klass();
    ciKlass* other_klass = other_type->klass();
+ 
    bool this_xk = this_type->klass_is_exact();
    bool other_xk = other_type->klass_is_exact();
    PTR this_ptr = this_type->ptr();
    PTR other_ptr = other_type->ptr();
    const TypeInterfaces* this_interfaces = this_type->interfaces();

*** 4356,35 ***
    // If a proper subtype is exact, and we return it, we return it exactly.
    // If a proper supertype is exact, there can be no subtyping relationship!
    // If both types are equal to the subtype, exactness is and-ed below the
    // centerline and or-ed above it.  (N.B. Constants are always exact.)
  
-   // Check for subtyping:
    const T* subtype = nullptr;
    bool subtype_exact = false;
    if (this_type->is_same_java_type_as(other_type)) {
      subtype = this_type;
      subtype_exact = below_centerline(ptr) ? (this_xk && other_xk) : (this_xk || other_xk);
    } else if (!other_xk && this_type->is_meet_subtype_of(other_type)) {
      subtype = this_type;     // Pick subtyping class
      subtype_exact = this_xk;
!   } else if(!this_xk && other_type->is_meet_subtype_of(this_type)) {
      subtype = other_type;    // Pick subtyping class
      subtype_exact = other_xk;
    }
  
!   if (subtype) {
!     if (above_centerline(ptr)) { // both are up?
        this_type = other_type = subtype;
        this_xk = other_xk = subtype_exact;
      } else if (above_centerline(this_ptr) && !above_centerline(other_ptr)) {
!       this_type = other_type; // tinst is down; keep down man
        this_xk = other_xk;
      } else if (above_centerline(other_ptr) && !above_centerline(this_ptr)) {
        other_type = this_type; // this is down; keep down man
-       other_xk = this_xk;
      } else {
        this_xk = subtype_exact;  // either they are equal, or we'll do an LCA
      }
    }
  
    // Check for classes now being equal
--- 4646,38 ---
    // If a proper subtype is exact, and we return it, we return it exactly.
    // If a proper supertype is exact, there can be no subtyping relationship!
    // If both types are equal to the subtype, exactness is and-ed below the
    // centerline and or-ed above it.  (N.B. Constants are always exact.)
  
    const T* subtype = nullptr;
    bool subtype_exact = false;
    if (this_type->is_same_java_type_as(other_type)) {
+     // Same klass
      subtype = this_type;
      subtype_exact = below_centerline(ptr) ? (this_xk && other_xk) : (this_xk || other_xk);
    } else if (!other_xk && this_type->is_meet_subtype_of(other_type)) {
      subtype = this_type;     // Pick subtyping class
      subtype_exact = this_xk;
!   } else if (!this_xk && other_type->is_meet_subtype_of(this_type)) {
      subtype = other_type;    // Pick subtyping class
      subtype_exact = other_xk;
    }
  
!   if (subtype != nullptr) {
!     if (above_centerline(ptr)) {
+       // Both types are empty.
        this_type = other_type = subtype;
        this_xk = other_xk = subtype_exact;
      } else if (above_centerline(this_ptr) && !above_centerline(other_ptr)) {
!       // this_type is empty while other_type is not. Take other_type.
+       this_type = other_type;
        this_xk = other_xk;
      } else if (above_centerline(other_ptr) && !above_centerline(this_ptr)) {
+       // other_type is empty while this_type is not. Take this_type.
        other_type = this_type; // this is down; keep down man
      } else {
+       // this_type and other_type are both non-empty.
        this_xk = subtype_exact;  // either they are equal, or we'll do an LCA
      }
    }
  
    // Check for classes now being equal

*** 4408,47 ***
    // Now we find the LCA of Java classes
    ciKlass* k = this_klass->least_common_ancestor(other_klass);
  
    res_klass = k;
    res_xk = false;
- 
    return LCA;
  }
  
  //------------------------java_mirror_type--------------------------------------
  ciType* TypeInstPtr::java_mirror_type() const {
    // must be a singleton type
    if( const_oop() == nullptr )  return nullptr;
  
    // must be of type java.lang.Class
    if( klass() != ciEnv::current()->Class_klass() )  return nullptr;
- 
    return const_oop()->as_instance()->java_mirror_type();
  }
  
  
  //------------------------------xdual------------------------------------------
  // Dual: do NOT dual on klasses.  This means I do NOT understand the Java
  // inheritance mechanism.
! const Type *TypeInstPtr::xdual() const {
!   return new TypeInstPtr(dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeInstPtr::eq( const Type *t ) const {
    const TypeInstPtr *p = t->is_instptr();
    return
      klass()->equals(p->klass()) &&
      _interfaces->eq(p->_interfaces) &&
      TypeOopPtr::eq(p);          // Check sub-type stuff
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
! uint TypeInstPtr::hash(void) const {
!   return klass()->hash() + TypeOopPtr::hash() + _interfaces->hash();
  }
  
  bool TypeInstPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
    return TypePtr::is_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
  }
--- 4701,81 ---
    // Now we find the LCA of Java classes
    ciKlass* k = this_klass->least_common_ancestor(other_klass);
  
    res_klass = k;
    res_xk = false;
    return LCA;
  }
  
+ //                Top-Flat    Flat        Not-Flat    Maybe-Flat
+ // -------------------------------------------------------------
+ //    Top-Flat    Top-Flat    Flat        Not-Flat    Maybe-Flat
+ //        Flat    Flat        Flat        Maybe-Flat  Maybe-Flat
+ //    Not-Flat    Not-Flat    Maybe-Flat  Not-Flat    Maybe-Flat
+ //  Maybe-Flat    Maybe-Flat  Maybe-Flat  Maybe-Flat  Maybe-flat
+ TypePtr::FlatInArray TypePtr::meet_flat_in_array(const FlatInArray left, const FlatInArray right) {
+   if (left == TopFlat) {
+     return right;
+   }
+   if (right == TopFlat) {
+     return left;
+   }
+   if (left == MaybeFlat || right == MaybeFlat) {
+     return MaybeFlat;
+   }
+ 
+   switch (left) {
+     case Flat:
+       if (right == Flat) {
+         return Flat;
+       }
+       return MaybeFlat;
+     case NotFlat:
+       if (right == NotFlat) {
+         return NotFlat;
+       }
+       return MaybeFlat;
+     default:
+       ShouldNotReachHere();
+       return Uninitialized;
+   }
+ }
+ 
  //------------------------java_mirror_type--------------------------------------
  ciType* TypeInstPtr::java_mirror_type() const {
    // must be a singleton type
    if( const_oop() == nullptr )  return nullptr;
  
    // must be of type java.lang.Class
    if( klass() != ciEnv::current()->Class_klass() )  return nullptr;
    return const_oop()->as_instance()->java_mirror_type();
  }
  
  
  //------------------------------xdual------------------------------------------
  // Dual: do NOT dual on klasses.  This means I do NOT understand the Java
  // inheritance mechanism.
! const Type* TypeInstPtr::xdual() const {
!   return new TypeInstPtr(dual_ptr(), klass(), _interfaces, klass_is_exact(), const_oop(), dual_offset(),
+                          dual_flat_in_array(), dual_instance_id(), dual_speculative(), dual_inline_depth());
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeInstPtr::eq( const Type *t ) const {
    const TypeInstPtr *p = t->is_instptr();
    return
      klass()->equals(p->klass()) &&
+     _flat_in_array == p->_flat_in_array &&
      _interfaces->eq(p->_interfaces) &&
      TypeOopPtr::eq(p);          // Check sub-type stuff
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
! uint TypeInstPtr::hash() const {
!   return klass()->hash() + TypeOopPtr::hash() + _interfaces->hash() + static_cast<uint>(_flat_in_array);
  }
  
  bool TypeInstPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
    return TypePtr::is_java_subtype_of_helper_for_instance(this, other, this_exact, other_exact);
  }

*** 4488,51 ***
    st->print(":%s", ptr_msg[_ptr]);
    if (_klass_is_exact) {
      st->print(":exact");
    }
  
    dump_offset(st);
    dump_instance_id(st);
    dump_inline_depth(st);
    dump_speculative(st);
  }
  #endif
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeInstPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), xadd_offset(offset),
                _instance_id, add_offset_speculative(offset), _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), offset,
                _instance_id, with_offset_speculative(offset), _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::remove_speculative() const {
    if (_speculative == nullptr) {
      return this;
    }
    assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset,
                _instance_id, nullptr, _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::with_speculative(const TypePtr* speculative) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _instance_id, speculative, _inline_depth);
  }
  
  const TypePtr* TypeInstPtr::with_inline_depth(int depth) const {
    if (!UseInlineDepthForSpeculativeTypes) {
      return this;
    }
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth);
  }
  
  const TypePtr* TypeInstPtr::with_instance_id(int instance_id) const {
    assert(is_known_instance(), "should be known");
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth);
  }
  
  const TypeKlassPtr* TypeInstPtr::as_klass_type(bool try_for_exact) const {
    bool xk = klass_is_exact();
    ciInstanceKlass* ik = klass()->as_instance_klass();
--- 4815,69 ---
    st->print(":%s", ptr_msg[_ptr]);
    if (_klass_is_exact) {
      st->print(":exact");
    }
  
+   st->print(" *");
+ 
    dump_offset(st);
    dump_instance_id(st);
    dump_inline_depth(st);
    dump_speculative(st);
+   dump_flat_in_array(_flat_in_array, st);
  }
  #endif
  
+ bool TypeInstPtr::empty() const {
+   if (_flat_in_array == TopFlat) {
+     return true;
+   }
+   return TypeOopPtr::empty();
+ }
+ 
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeInstPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), xadd_offset(offset), _flat_in_array,
                _instance_id, add_offset_speculative(offset), _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), Offset(offset), _flat_in_array,
                _instance_id, with_offset_speculative(offset), _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::remove_speculative() const {
    if (_speculative == nullptr) {
      return this;
    }
    assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _flat_in_array,
                _instance_id, nullptr, _inline_depth);
  }
  
  const TypeInstPtr* TypeInstPtr::with_speculative(const TypePtr* speculative) const {
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _flat_in_array, _instance_id, speculative, _inline_depth);
  }
  
  const TypePtr* TypeInstPtr::with_inline_depth(int depth) const {
    if (!UseInlineDepthForSpeculativeTypes) {
      return this;
    }
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _flat_in_array, _instance_id, _speculative, depth);
  }
  
  const TypePtr* TypeInstPtr::with_instance_id(int instance_id) const {
    assert(is_known_instance(), "should be known");
!   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, _flat_in_array, instance_id, _speculative, _inline_depth);
+ }
+ 
+ const TypeInstPtr *TypeInstPtr::cast_to_flat_in_array() const {
+   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, Flat, _instance_id, _speculative, _inline_depth);
+ }
+ 
+ const TypeInstPtr *TypeInstPtr::cast_to_maybe_flat_in_array() const {
+   return make(_ptr, klass(), _interfaces, klass_is_exact(), const_oop(), _offset, MaybeFlat, _instance_id, _speculative, _inline_depth);
  }
  
  const TypeKlassPtr* TypeInstPtr::as_klass_type(bool try_for_exact) const {
    bool xk = klass_is_exact();
    ciInstanceKlass* ik = klass()->as_instance_klass();

*** 4542,11 ***
        Dependencies* deps = C->dependencies();
        deps->assert_leaf_type(ik);
        xk = true;
      }
    }
!   return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), _interfaces, 0);
  }
  
  template <class T1, class T2> bool TypePtr::is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk) {
    static_assert(std::is_base_of<T2, T1>::value, "");
  
--- 4887,12 ---
        Dependencies* deps = C->dependencies();
        deps->assert_leaf_type(ik);
        xk = true;
      }
    }
!   FlatInArray flat_in_array = compute_flat_in_array_if_unknown(ik, xk, _flat_in_array);
+   return TypeInstKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, klass(), _interfaces, Offset(0), flat_in_array);
  }
  
  template <class T1, class T2> bool TypePtr::is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk) {
    static_assert(std::is_base_of<T2, T1>::value, "");
  

*** 4587,11 ***
    const TypePtr* other_elem = other_ary->elem()->make_ptr();
    const TypePtr* this_elem = this_one->elem()->make_ptr();
    if (other_elem != nullptr && this_elem != nullptr) {
      return this_one->is_reference_type(this_elem)->is_meet_subtype_of_helper(this_one->is_reference_type(other_elem), this_xk, other_xk);
    }
- 
    if (other_elem == nullptr && this_elem == nullptr) {
      return this_one->klass()->is_subtype_of(other->klass());
    }
  
    return false;
--- 4933,10 ---

*** 4610,37 ***
  }
  
  //=============================================================================
  // Convenience common pre-built types.
  const TypeAryPtr* TypeAryPtr::BOTTOM;
! const TypeAryPtr* TypeAryPtr::RANGE;
! const TypeAryPtr* TypeAryPtr::OOPS;
! const TypeAryPtr* TypeAryPtr::NARROWOOPS;
! const TypeAryPtr* TypeAryPtr::BYTES;
! const TypeAryPtr* TypeAryPtr::SHORTS;
! const TypeAryPtr* TypeAryPtr::CHARS;
! const TypeAryPtr* TypeAryPtr::INTS;
! const TypeAryPtr* TypeAryPtr::LONGS;
! const TypeAryPtr* TypeAryPtr::FLOATS;
! const TypeAryPtr* TypeAryPtr::DOUBLES;
  
  //------------------------------make-------------------------------------------
! const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,
                                     int instance_id, const TypePtr* speculative, int inline_depth) {
    assert(!(k == nullptr && ary->_elem->isa_int()),
           "integral arrays must be pre-equipped with a class");
    if (!xk)  xk = ary->ary_must_be_exact();
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
    if (k != nullptr && k->is_loaded() && k->is_obj_array_klass() &&
        k->as_obj_array_klass()->base_element_klass()->is_interface()) {
      k = nullptr;
    }
!   return (TypeAryPtr*)(new TypeAryPtr(ptr, nullptr, ary, k, xk, offset, instance_id, false, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------make-------------------------------------------
! const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset,
                                     int instance_id, const TypePtr* speculative, int inline_depth,
                                     bool is_autobox_cache) {
    assert(!(k == nullptr && ary->_elem->isa_int()),
           "integral arrays must be pre-equipped with a class");
    assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
--- 4955,38 ---
  }
  
  //=============================================================================
  // Convenience common pre-built types.
  const TypeAryPtr* TypeAryPtr::BOTTOM;
! const TypeAryPtr *TypeAryPtr::RANGE;
! const TypeAryPtr *TypeAryPtr::OOPS;
! const TypeAryPtr *TypeAryPtr::NARROWOOPS;
! const TypeAryPtr *TypeAryPtr::BYTES;
! const TypeAryPtr *TypeAryPtr::SHORTS;
! const TypeAryPtr *TypeAryPtr::CHARS;
! const TypeAryPtr *TypeAryPtr::INTS;
! const TypeAryPtr *TypeAryPtr::LONGS;
! const TypeAryPtr *TypeAryPtr::FLOATS;
! const TypeAryPtr *TypeAryPtr::DOUBLES;
+ const TypeAryPtr *TypeAryPtr::INLINES;
  
  //------------------------------make-------------------------------------------
! const TypeAryPtr* TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset,
                                     int instance_id, const TypePtr* speculative, int inline_depth) {
    assert(!(k == nullptr && ary->_elem->isa_int()),
           "integral arrays must be pre-equipped with a class");
    if (!xk)  xk = ary->ary_must_be_exact();
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
    if (k != nullptr && k->is_loaded() && k->is_obj_array_klass() &&
        k->as_obj_array_klass()->base_element_klass()->is_interface()) {
      k = nullptr;
    }
!   return (TypeAryPtr*)(new TypeAryPtr(ptr, nullptr, ary, k, xk, offset, field_offset, instance_id, false, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------make-------------------------------------------
! const TypeAryPtr* TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset,
                                     int instance_id, const TypePtr* speculative, int inline_depth,
                                     bool is_autobox_cache) {
    assert(!(k == nullptr && ary->_elem->isa_int()),
           "integral arrays must be pre-equipped with a class");
    assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );

*** 4648,31 ***
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
    if (k != nullptr && k->is_loaded() && k->is_obj_array_klass() &&
        k->as_obj_array_klass()->base_element_klass()->is_interface()) {
      k = nullptr;
    }
!   return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
    if( ptr == _ptr ) return this;
!   return make(ptr, ptr == Constant ? const_oop() : nullptr, _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
  }
  
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
    if( klass_is_exact == _klass_is_exact ) return this;
    if (_ary->ary_must_be_exact())  return this;  // cannot clear xk
!   return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative, _inline_depth);
  }
  
  //-----------------------------cast_to_instance_id----------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_instance_id(int instance_id) const {
    if( instance_id == _instance_id ) return this;
!   return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
  }
  
  
  //-----------------------------max_array_length-------------------------------
  // A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization.
--- 4994,31 ---
    assert(instance_id <= 0 || xk, "instances are always exactly typed");
    if (k != nullptr && k->is_loaded() && k->is_obj_array_klass() &&
        k->as_obj_array_klass()->base_element_klass()->is_interface()) {
      k = nullptr;
    }
!   return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, field_offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
    if( ptr == _ptr ) return this;
!   return make(ptr, ptr == Constant ? const_oop() : nullptr, _ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
  }
  
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
    if( klass_is_exact == _klass_is_exact ) return this;
    if (_ary->ary_must_be_exact())  return this;  // cannot clear xk
!   return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
  }
  
  //-----------------------------cast_to_instance_id----------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_instance_id(int instance_id) const {
    if( instance_id == _instance_id ) return this;
!   return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth, _is_autobox_cache);
  }
  
  
  //-----------------------------max_array_length-------------------------------
  // A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization.

*** 4726,12 ***
  //-------------------------------cast_to_size----------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const {
    assert(new_size != nullptr, "");
    new_size = narrow_size_type(new_size);
    if (new_size == size())  return this;
!   const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
  }
  
  //------------------------------cast_to_stable---------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
    if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))
--- 5072,109 ---
  //-------------------------------cast_to_size----------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const {
    assert(new_size != nullptr, "");
    new_size = narrow_size_type(new_size);
    if (new_size == size())  return this;
!   const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic());
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+ }
+ 
+ const TypeAryPtr* TypeAryPtr::cast_to_flat(bool flat) const {
+   if (flat == is_flat()) {
+     return this;
+   }
+   assert(!flat || !is_not_flat(), "inconsistency");
+   const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), flat, is_not_flat(), is_not_null_free(), is_atomic());
+   const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+   if (res->speculative() == res->remove_speculative()) {
+     return res->remove_speculative();
+   }
+   return res;
+ }
+ 
+ //-------------------------------cast_to_not_flat------------------------------
+ const TypeAryPtr* TypeAryPtr::cast_to_not_flat(bool not_flat) const {
+   if (not_flat == is_not_flat()) {
+     return this;
+   }
+   assert(!not_flat || !is_flat(), "inconsistency");
+   const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), not_flat, is_not_null_free(), is_atomic());
+   const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+   // We keep the speculative part if it contains information about flat-/nullability.
+   // Make sure it's removed if it's not better than the non-speculative type anymore.
+   if (res->speculative() == res->remove_speculative()) {
+     return res->remove_speculative();
+   }
+   return res;
+ }
+ 
+ const TypeAryPtr* TypeAryPtr::cast_to_null_free(bool null_free) const {
+   if (null_free == is_null_free()) {
+     return this;
+   }
+   assert(!null_free || !is_not_null_free(), "inconsistency");
+   const Type* elem = this->elem();
+   const Type* new_elem = elem->make_ptr();
+   if (null_free) {
+     new_elem = new_elem->join_speculative(TypePtr::NOTNULL);
+   } else {
+     new_elem = new_elem->meet_speculative(TypePtr::NULL_PTR);
+   }
+   new_elem = elem->isa_narrowoop() ? new_elem->make_narrowoop() : new_elem;
+   const TypeAry* new_ary = TypeAry::make(new_elem, size(), is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic());
+   const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+   if (res->speculative() == res->remove_speculative()) {
+     return res->remove_speculative();
+   }
+   return res;
+ }
+ 
+ //-------------------------------cast_to_not_null_free-------------------------
+ const TypeAryPtr* TypeAryPtr::cast_to_not_null_free(bool not_null_free) const {
+   if (not_null_free == is_not_null_free()) {
+     return this;
+   }
+   assert(!not_null_free || !is_null_free(), "inconsistency");
+   const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), is_flat(), is_not_flat(), not_null_free, is_atomic());
+   const TypeAryPtr* res = make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset,
+                                _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+   // We keep the speculative part if it contains information about flat-/nullability.
+   // Make sure it's removed if it's not better than the non-speculative type anymore.
+   if (res->speculative() == res->remove_speculative()) {
+     return res->remove_speculative();
+   }
+   return res;
+ }
+ 
+ //---------------------------------update_properties---------------------------
+ const TypeAryPtr* TypeAryPtr::update_properties(const TypeAryPtr* from) const {
+   if ((from->is_flat()          && is_not_flat()) ||
+       (from->is_not_flat()      && is_flat()) ||
+       (from->is_null_free()     && is_not_null_free()) ||
+       (from->is_not_null_free() && is_null_free())) {
+     return nullptr; // Inconsistent properties
+   }
+   const TypeAryPtr* res = this;
+   if (from->is_not_null_free()) {
+     res = res->cast_to_not_null_free();
+   }
+   if (from->is_not_flat()) {
+     res = res->cast_to_not_flat();
+   }
+   return res;
+ }
+ 
+ jint TypeAryPtr::flat_layout_helper() const {
+   return exact_klass()->as_flat_array_klass()->layout_helper();
+ }
+ 
+ int TypeAryPtr::flat_elem_size() const {
+   return exact_klass()->as_flat_array_klass()->element_byte_size();
+ }
+ 
+ int TypeAryPtr::flat_log_elem_size() const {
+   return exact_klass()->as_flat_array_klass()->log2_element_size();
  }
  
  //------------------------------cast_to_stable---------------------------------
  const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
    if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))

*** 4743,13 ***
    if (stable_dimension > 1 && elem_ptr != nullptr && elem_ptr->isa_aryptr()) {
      // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
      elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
    }
  
!   const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
  
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
  }
  
  //-----------------------------stable_dimension--------------------------------
  int TypeAryPtr::stable_dimension() const {
    if (!is_stable())  return 0;
--- 5186,13 ---
    if (stable_dimension > 1 && elem_ptr != nullptr && elem_ptr->isa_aryptr()) {
      // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
      elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
    }
  
!   const TypeAry* new_ary = TypeAry::make(elem, size(), stable, is_flat(), is_not_flat(), is_not_null_free(), is_atomic());
  
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
  }
  
  //-----------------------------stable_dimension--------------------------------
  int TypeAryPtr::stable_dimension() const {
    if (!is_stable())  return 0;

*** 4765,27 ***
    if (is_autobox_cache())  return this;
    const TypeOopPtr* etype = elem()->make_oopptr();
    if (etype == nullptr)  return this;
    // The pointers in the autobox arrays are always non-null.
    etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
!   const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable());
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth, /*is_autobox_cache=*/true);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAryPtr::eq( const Type *t ) const {
    const TypeAryPtr *p = t->is_aryptr();
    return
      _ary == p->_ary &&  // Check array
!     TypeOopPtr::eq(p);  // Check sub-parts
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAryPtr::hash(void) const {
!   return (uint)(uintptr_t)_ary + TypeOopPtr::hash();
  }
  
  bool TypeAryPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
    return TypePtr::is_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
  }
--- 5208,28 ---
    if (is_autobox_cache())  return this;
    const TypeOopPtr* etype = elem()->make_oopptr();
    if (etype == nullptr)  return this;
    // The pointers in the autobox arrays are always non-null.
    etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
!   const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable(), is_flat(), is_not_flat(), is_not_null_free(), is_atomic());
!   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, /*is_autobox_cache=*/true);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAryPtr::eq( const Type *t ) const {
    const TypeAryPtr *p = t->is_aryptr();
    return
      _ary == p->_ary &&  // Check array
!     TypeOopPtr::eq(p) &&// Check sub-parts
+     _field_offset == p->_field_offset;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAryPtr::hash(void) const {
!   return (uint)(uintptr_t)_ary + TypeOopPtr::hash() + _field_offset.get();
  }
  
  bool TypeAryPtr::is_java_subtype_of_helper(const TypeOopPtr* other, bool this_exact, bool other_exact) const {
    return TypePtr::is_java_subtype_of_helper_for_array(this, other, this_exact, other_exact);
  }

*** 4828,20 ***
      typerr(t);
  
    case OopPtr: {                // Meeting to OopPtrs
      // Found a OopPtr type vs self-AryPtr type
      const TypeOopPtr *tp = t->is_oopptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int depth = meet_inline_depth(tp->inline_depth());
      const TypePtr* speculative = xmeet_speculative(tp);
      switch (tp->ptr()) {
      case TopPTR:
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                   _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
      }
      case BotPTR:
      case NotNull: {
        int instance_id = meet_instance_id(tp->instance_id());
        return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
--- 5272,20 ---
      typerr(t);
  
    case OopPtr: {                // Meeting to OopPtrs
      // Found a OopPtr type vs self-AryPtr type
      const TypeOopPtr *tp = t->is_oopptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int depth = meet_inline_depth(tp->inline_depth());
      const TypePtr* speculative = xmeet_speculative(tp);
      switch (tp->ptr()) {
      case TopPTR:
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                   _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
      }
      case BotPTR:
      case NotNull: {
        int instance_id = meet_instance_id(tp->instance_id());
        return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);

*** 4851,11 ***
    }
  
    case AnyPtr: {                // Meeting two AnyPtrs
      // Found an AnyPtr type vs self-AryPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {
      case TopPTR:
--- 5295,11 ---
    }
  
    case AnyPtr: {                // Meeting two AnyPtrs
      // Found an AnyPtr type vs self-AryPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      switch (tp->ptr()) {
      case TopPTR:

*** 4867,11 ***
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
        // else fall through to AnyNull
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                   _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
      }
      default: ShouldNotReachHere();
      }
    }
  
--- 5311,11 ---
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
        // else fall through to AnyNull
      case AnyNull: {
        int instance_id = meet_instance_id(InstanceTop);
        return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                   _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
      }
      default: ShouldNotReachHere();
      }
    }
  

*** 4881,11 ***
    case AryKlassPtr:
    case RawPtr: return TypePtr::BOTTOM;
  
    case AryPtr: {                // Meeting 2 references?
      const TypeAryPtr *tap = t->is_aryptr();
!     int off = meet_offset(tap->offset());
      const Type* tm = _ary->meet_speculative(tap->_ary);
      const TypeAry* tary = tm->isa_ary();
      if (tary == nullptr) {
        assert(tm == Type::TOP || tm == Type::BOTTOM, "");
        return tm;
--- 5325,12 ---
    case AryKlassPtr:
    case RawPtr: return TypePtr::BOTTOM;
  
    case AryPtr: {                // Meeting 2 references?
      const TypeAryPtr *tap = t->is_aryptr();
!     Offset off = meet_offset(tap->offset());
+     Offset field_off = meet_field_offset(tap->field_offset());
      const Type* tm = _ary->meet_speculative(tap->_ary);
      const TypeAry* tary = tm->isa_ary();
      if (tary == nullptr) {
        assert(tm == Type::TOP || tm == Type::BOTTOM, "");
        return tm;

*** 4895,13 ***
      const TypePtr* speculative = xmeet_speculative(tap);
      int depth = meet_inline_depth(tap->inline_depth());
  
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
      const Type* elem = tary->_elem;
!     if (meet_aryptr(ptr, elem, this, tap, res_klass, res_xk) == NOT_SUBTYPE) {
        instance_id = InstanceBot;
      }
  
      ciObject* o = nullptr;             // Assume not constant when done
      ciObject* this_oop = const_oop();
      ciObject* tap_oop = tap->const_oop();
--- 5340,31 ---
      const TypePtr* speculative = xmeet_speculative(tap);
      int depth = meet_inline_depth(tap->inline_depth());
  
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
+     bool res_flat = false;
+     bool res_not_flat = false;
+     bool res_not_null_free = false;
+     bool res_atomic = false;
      const Type* elem = tary->_elem;
!     if (meet_aryptr(ptr, elem, this, tap, res_klass, res_xk, res_flat, res_not_flat, res_not_null_free, res_atomic) == NOT_SUBTYPE) {
        instance_id = InstanceBot;
+     } else if (this->is_flat() != tap->is_flat()) {
+       // Meeting flat inline type array with non-flat array. Adjust (field) offset accordingly.
+       if (tary->_flat) {
+         // Result is in a flat representation
+         off = Offset(is_flat() ? offset() : tap->offset());
+         field_off = is_flat() ? field_offset() : tap->field_offset();
+       } else if (below_centerline(ptr)) {
+         // Result is in a non-flat representation
+         off = Offset(flat_offset()).meet(Offset(tap->flat_offset()));
+         field_off = (field_off == Offset::top) ? Offset::top : Offset::bottom;
+       } else if (flat_offset() == tap->flat_offset()) {
+         off = Offset(!is_flat() ? offset() : tap->offset());
+         field_off = !is_flat() ? field_offset() : tap->field_offset();
+       }
      }
  
      ciObject* o = nullptr;             // Assume not constant when done
      ciObject* this_oop = const_oop();
      ciObject* tap_oop = tap->const_oop();

*** 4915,17 ***
          o = this_oop;
        } else {
          ptr = NotNull;
        }
      }
!     return make(ptr, o, TypeAry::make(elem, tary->_size, tary->_stable), res_klass, res_xk, off, instance_id, speculative, depth);
    }
  
    // All arrays inherit from Object class
    case InstPtr: {
      const TypeInstPtr *tp = t->is_instptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int instance_id = meet_instance_id(tp->instance_id());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      const TypeInterfaces* interfaces = meet_interfaces(tp);
--- 5378,17 ---
          o = this_oop;
        } else {
          ptr = NotNull;
        }
      }
!     return make(ptr, o, TypeAry::make(elem, tary->_size, tary->_stable, res_flat, res_not_flat, res_not_null_free, res_atomic), res_klass, res_xk, off, field_off, instance_id, speculative, depth);
    }
  
    // All arrays inherit from Object class
    case InstPtr: {
      const TypeInstPtr *tp = t->is_instptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      int instance_id = meet_instance_id(tp->instance_id());
      const TypePtr* speculative = xmeet_speculative(tp);
      int depth = meet_inline_depth(tp->inline_depth());
      const TypeInterfaces* interfaces = meet_interfaces(tp);

*** 4936,72 ***
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
!       if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && !tp->klass_is_exact()) {
!         return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          instance_id = InstanceBot;
          interfaces = this_interfaces->intersection_with(tp_interfaces);
!         return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr,offset, instance_id, speculative, depth);
        }
      case Constant:
      case NotNull:
!     case BotPTR:                // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if (above_centerline(tp->ptr())) {
          // If 'tp'  is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
!         if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && !tp->klass_is_exact()) {
            // that is, my array type is a subtype of 'tp' klass
            return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                       _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
          }
        }
        // The other case cannot happen, since t cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if (ptr == Constant) {
!          ptr = NotNull;
        }
        if (instance_id > 0) {
          instance_id = InstanceBot;
        }
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, instance_id, speculative, depth);
      default: typerr(t);
      }
    }
    }
    return this;                  // Lint noise
  }
  
  
! template<class T> TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary,
!                                                            const T* other_ary, ciKlass*& res_klass, bool& res_xk) {
    int dummy;
    bool this_top_or_bottom = (this_ary->base_element_type(dummy) == Type::TOP || this_ary->base_element_type(dummy) == Type::BOTTOM);
    bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
    ciKlass* this_klass = this_ary->klass();
    ciKlass* other_klass = other_ary->klass();
    bool this_xk = this_ary->klass_is_exact();
    bool other_xk = other_ary->klass_is_exact();
    PTR this_ptr = this_ary->ptr();
    PTR other_ptr = other_ary->ptr();
    res_klass = nullptr;
    MeetResult result = SUBTYPE;
    if (elem->isa_int()) {
      // Integral array element types have irrelevant lattice relations.
      // It is the klass that determines array layout, not the element type.
!     if (this_top_or_bottom)
!       res_klass = other_klass;
!     else if (other_top_or_bottom || other_klass == this_klass) {
        res_klass = this_klass;
      } else {
        // Something like byte[int+] meets char[int+].
        // This must fall to bottom, not (int[-128..65535])[int+].
        // instance_id = InstanceBot;
--- 5399,107 ---
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
!       //
!       // Flat in array:
+       // We do
+       //   dual(TypeAryPtr) MEET dual(TypeInstPtr)
+       // If TypeInstPtr is anything else than Object, then the result of the meet is bottom Object (i.e. we could have
+       // instances or arrays).
+       // If TypeInstPtr is an Object and either
+       // - exact
+       // - inexact AND flat in array == dual(not flat in array) (i.e. not an array type)
+       // then the result of the meet is bottom Object (i.e. we could have instances or arrays).
+       // Otherwise, we meet two array pointers and create a new TypeAryPtr.
+       if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
+           !tp->klass_is_exact() && !tp->is_not_flat_in_array()) {
+         return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          instance_id = InstanceBot;
          interfaces = this_interfaces->intersection_with(tp_interfaces);
!         FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array());
+         return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset, flat_in_array, instance_id, speculative, depth);
        }
      case Constant:
      case NotNull:
!     case BotPTR: { // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if (above_centerline(tp->ptr())) {
          // If 'tp'  is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
! 
+         // Flat in array: We do TypeAryPtr MEET dual(TypeInstPtr), same applies as above in TopPTR/AnyNull case.
+         if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
+             !tp->klass_is_exact() && !tp->is_not_flat_in_array()) {
            // that is, my array type is a subtype of 'tp' klass
            return make(ptr, (ptr == Constant ? const_oop() : nullptr),
!                       _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
          }
        }
        // The other case cannot happen, since t cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if (ptr == Constant) {
!         ptr = NotNull;
        }
        if (instance_id > 0) {
          instance_id = InstanceBot;
        }
+ 
+       FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array());
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, nullptr, offset,
+                                flat_in_array, instance_id, speculative, depth);
+     }
      default: typerr(t);
      }
    }
    }
    return this;                  // Lint noise
  }
  
  
! template<class T> TypePtr::MeetResult TypePtr::meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary,
!                                                            ciKlass*& res_klass, bool& res_xk, bool &res_flat, bool& res_not_flat, bool& res_not_null_free, bool &res_atomic) {
    int dummy;
    bool this_top_or_bottom = (this_ary->base_element_type(dummy) == Type::TOP || this_ary->base_element_type(dummy) == Type::BOTTOM);
    bool other_top_or_bottom = (other_ary->base_element_type(dummy) == Type::TOP || other_ary->base_element_type(dummy) == Type::BOTTOM);
    ciKlass* this_klass = this_ary->klass();
    ciKlass* other_klass = other_ary->klass();
    bool this_xk = this_ary->klass_is_exact();
    bool other_xk = other_ary->klass_is_exact();
    PTR this_ptr = this_ary->ptr();
    PTR other_ptr = other_ary->ptr();
+   bool this_flat = this_ary->is_flat();
+   bool this_not_flat = this_ary->is_not_flat();
+   bool other_flat = other_ary->is_flat();
+   bool other_not_flat = other_ary->is_not_flat();
+   bool this_not_null_free = this_ary->is_not_null_free();
+   bool other_not_null_free = other_ary->is_not_null_free();
+   bool this_atomic = this_ary->is_atomic();
+   bool other_atomic = other_ary->is_atomic();
+   const bool same_nullness = this_ary->is_null_free() == other_ary->is_null_free();
    res_klass = nullptr;
    MeetResult result = SUBTYPE;
+   res_flat = this_flat && other_flat;
+   bool res_null_free = this_ary->is_null_free() && other_ary->is_null_free();
+   res_not_flat = this_not_flat && other_not_flat;
+   res_not_null_free = this_not_null_free && other_not_null_free;
+   res_atomic = this_atomic && other_atomic;
+ 
    if (elem->isa_int()) {
      // Integral array element types have irrelevant lattice relations.
      // It is the klass that determines array layout, not the element type.
!       if (this_top_or_bottom) {
!         res_klass = other_klass;
!       } else if (other_top_or_bottom || other_klass == this_klass) {
        res_klass = this_klass;
      } else {
        // Something like byte[int+] meets char[int+].
        // This must fall to bottom, not (int[-128..65535])[int+].
        // instance_id = InstanceBot;

*** 5039,35 ***
      case AnyNull:
      case TopPTR:
        // Compute new klass on demand, do not use tap->_klass
        if (below_centerline(this_ptr)) {
          res_xk = this_xk;
        } else {
          res_xk = (other_xk || this_xk);
        }
!       return result;
      case Constant: {
!       if (this_ptr == Constant) {
          res_xk = true;
!       } else if(above_centerline(this_ptr)) {
          res_xk = true;
        } else {
          // Only precise for identical arrays
          res_xk = this_xk && (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom));
        }
!       return result;
      }
      case NotNull:
      case BotPTR:
        // Compute new klass on demand, do not use tap->_klass
        if (above_centerline(this_ptr)) {
          res_xk = other_xk;
        } else {
          res_xk = (other_xk && this_xk) &&
                   (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom)); // Only precise for identical arrays
        }
!       return result;
      default:  {
        ShouldNotReachHere();
        return result;
      }
    }
--- 5537,55 ---
      case AnyNull:
      case TopPTR:
        // Compute new klass on demand, do not use tap->_klass
        if (below_centerline(this_ptr)) {
          res_xk = this_xk;
+         if (this_ary->is_flat()) {
+           elem = this_ary->elem();
+         }
        } else {
          res_xk = (other_xk || this_xk);
        }
!       break;
      case Constant: {
!       if (this_ptr == Constant && same_nullness) {
+         // Only exact if same nullness since:
+         //     null-free [LMyValue <: nullable [LMyValue.
          res_xk = true;
!       } else if (above_centerline(this_ptr)) {
          res_xk = true;
        } else {
          // Only precise for identical arrays
          res_xk = this_xk && (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom));
+         // Even though MyValue is final, [LMyValue is only exact if the array
+         // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue.
+         if (res_xk && !res_null_free && !res_not_null_free) {
+           ptr = NotNull;
+           res_xk = false;
+         }
        }
!       break;
      }
      case NotNull:
      case BotPTR:
        // Compute new klass on demand, do not use tap->_klass
        if (above_centerline(this_ptr)) {
          res_xk = other_xk;
+         if (other_ary->is_flat()) {
+           elem = other_ary->elem();
+         }
        } else {
          res_xk = (other_xk && this_xk) &&
                   (this_ary->is_same_java_type_as(other_ary) || (this_top_or_bottom && other_top_or_bottom)); // Only precise for identical arrays
+         // Even though MyValue is final, [LMyValue is only exact if the array
+         // is (not) null-free due to null-free [LMyValue <: null-able [LMyValue.
+         if (res_xk && !res_null_free && !res_not_null_free) {
+           ptr = NotNull;
+           res_xk = false;
+         }
        }
!       break;
      default:  {
        ShouldNotReachHere();
        return result;
      }
    }

*** 5076,11 ***
  
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type *TypeAryPtr::xdual() const {
!   return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
  }
  
  //------------------------------dump2------------------------------------------
  #ifndef PRODUCT
  void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
--- 5594,21 ---
  
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type *TypeAryPtr::xdual() const {
!   bool xk = _klass_is_exact;
+   return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(), _klass, xk, dual_offset(), dual_field_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
+ }
+ 
+ Type::Offset TypeAryPtr::meet_field_offset(const Type::Offset offset) const {
+   return _field_offset.meet(offset);
+ }
+ 
+ //------------------------------dual_offset------------------------------------
+ Type::Offset TypeAryPtr::dual_field_offset() const {
+   return _field_offset.dual();
  }
  
  //------------------------------dump2------------------------------------------
  #ifndef PRODUCT
  void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {

*** 5095,22 ***
    st->print(":%s", ptr_msg[_ptr]);
    if (_klass_is_exact) {
      st->print(":exact");
    }
  
!   if( _offset != 0 ) {
      BasicType basic_elem_type = elem()->basic_type();
      int header_size = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
!     if( _offset == OffsetTop )       st->print("+undefined");
!     else if( _offset == OffsetBot )  st->print("+any");
!     else if( _offset < header_size ) st->print("+%d", _offset);
      else {
        if (basic_elem_type == T_ILLEGAL) {
          st->print("+any");
        } else {
          int elem_size = type2aelembytes(basic_elem_type);
!         st->print("[%d]", (_offset - header_size)/elem_size);
        }
      }
    }
  
    dump_instance_id(st);
--- 5623,44 ---
    st->print(":%s", ptr_msg[_ptr]);
    if (_klass_is_exact) {
      st->print(":exact");
    }
  
!   if (is_flat()) {
+     st->print(":flat");
+     st->print("(");
+     _field_offset.dump2(st);
+     st->print(")");
+   } else if (is_not_flat()) {
+     st->print(":not_flat");
+   }
+   if (is_null_free()) {
+     st->print(":null free");
+   }
+   if (is_atomic()) {
+     st->print(":atomic");
+   }
+   if (Verbose) {
+     if (is_not_flat()) {
+       st->print(":not flat");
+     }
+     if (is_not_null_free()) {
+       st->print(":nullable");
+     }
+   }
+   if (offset() != 0) {
      BasicType basic_elem_type = elem()->basic_type();
      int header_size = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
!     if( _offset == Offset::top )       st->print("+undefined");
!     else if( _offset == Offset::bottom )  st->print("+any");
!     else if( offset() < header_size ) st->print("+%d", offset());
      else {
        if (basic_elem_type == T_ILLEGAL) {
          st->print("+any");
        } else {
          int elem_size = type2aelembytes(basic_elem_type);
!         st->print("[%d]", (offset() - header_size)/elem_size);
        }
      }
    }
  
    dump_instance_id(st);

*** 5119,48 ***
  }
  #endif
  
  bool TypeAryPtr::empty(void) const {
    if (_ary->empty())       return true;
    return TypeOopPtr::empty();
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeAryPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
  }
  
  const TypeAryPtr* TypeAryPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, offset, _instance_id, with_offset_speculative(offset), _inline_depth);
  }
  
  const TypeAryPtr* TypeAryPtr::with_ary(const TypeAry* ary) const {
!   return make(_ptr, _const_oop, ary, _klass, _klass_is_exact, _offset, _instance_id, _speculative, _inline_depth);
  }
  
  const TypeAryPtr* TypeAryPtr::remove_speculative() const {
    if (_speculative == nullptr) {
      return this;
    }
    assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, nullptr, _inline_depth);
  }
  
  const TypePtr* TypeAryPtr::with_inline_depth(int depth) const {
    if (!UseInlineDepthForSpeculativeTypes) {
      return this;
    }
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth);
  }
  
  const TypePtr* TypeAryPtr::with_instance_id(int instance_id) const {
    assert(is_known_instance(), "should be known");
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
  }
  
  //=============================================================================
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeNarrowPtr::hash(void) const {
    return _ptrtype->hash() + 7;
  }
--- 5669,109 ---
  }
  #endif
  
  bool TypeAryPtr::empty(void) const {
    if (_ary->empty())       return true;
+   // FIXME: Does this belong here? Or in the meet code itself?
+   if (is_flat() && is_not_flat()) {
+     return true;
+   }
    return TypeOopPtr::empty();
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeAryPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _field_offset, _instance_id, add_offset_speculative(offset), _inline_depth, _is_autobox_cache);
  }
  
  const TypeAryPtr* TypeAryPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, Offset(offset), _field_offset, _instance_id, with_offset_speculative(offset), _inline_depth, _is_autobox_cache);
  }
  
  const TypeAryPtr* TypeAryPtr::with_ary(const TypeAry* ary) const {
!   return make(_ptr, _const_oop, ary, _klass, _klass_is_exact, _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
  }
  
  const TypeAryPtr* TypeAryPtr::remove_speculative() const {
    if (_speculative == nullptr) {
      return this;
    }
    assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, nullptr, _inline_depth, _is_autobox_cache);
+ }
+ 
+ const Type* TypeAryPtr::cleanup_speculative() const {
+   if (speculative() == nullptr) {
+     return this;
+   }
+   // Keep speculative part if it contains information about flat-/nullability
+   const TypeAryPtr* spec_aryptr = speculative()->isa_aryptr();
+   if (spec_aryptr != nullptr && !above_centerline(spec_aryptr->ptr()) &&
+       (spec_aryptr->is_not_flat() || spec_aryptr->is_not_null_free())) {
+     return this;
+   }
+   return TypeOopPtr::cleanup_speculative();
  }
  
  const TypePtr* TypeAryPtr::with_inline_depth(int depth) const {
    if (!UseInlineDepthForSpeculativeTypes) {
      return this;
    }
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, _speculative, depth, _is_autobox_cache);
+ }
+ 
+ const TypeAryPtr* TypeAryPtr::with_field_offset(int offset) const {
+   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, Offset(offset), _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+ }
+ 
+ const TypePtr* TypeAryPtr::add_field_offset_and_offset(intptr_t offset) const {
+   int adj = 0;
+   if (is_flat() && klass_is_exact() && offset != Type::OffsetBot && offset != Type::OffsetTop) {
+     if (_offset.get() != OffsetBot && _offset.get() != OffsetTop) {
+       adj = _offset.get();
+       offset += _offset.get();
+     }
+     uint header = arrayOopDesc::base_offset_in_bytes(T_FLAT_ELEMENT);
+     if (_field_offset.get() != OffsetBot && _field_offset.get() != OffsetTop) {
+       offset += _field_offset.get();
+       if (_offset.get() == OffsetBot || _offset.get() == OffsetTop) {
+         offset += header;
+       }
+     }
+     if (elem()->make_oopptr()->is_inlinetypeptr() && (offset >= (intptr_t)header || offset < 0)) {
+       // Try to get the field of the inline type array element we are pointing to
+       ciInlineKlass* vk = elem()->inline_klass();
+       int shift = flat_log_elem_size();
+       int mask = (1 << shift) - 1;
+       intptr_t field_offset = ((offset - header) & mask);
+       ciField* field = vk->get_field_by_offset(field_offset + vk->payload_offset(), false);
+       if (field != nullptr || field_offset == vk->null_marker_offset_in_payload()) {
+         return with_field_offset(field_offset)->add_offset(offset - field_offset - adj);
+       }
+     }
+   }
+   return add_offset(offset - adj);
+ }
+ 
+ // Return offset incremented by field_offset for flat inline type arrays
+ int TypeAryPtr::flat_offset() const {
+   int offset = _offset.get();
+   if (offset != Type::OffsetBot && offset != Type::OffsetTop &&
+       _field_offset != Offset::bottom && _field_offset != Offset::top) {
+     offset += _field_offset.get();
+   }
+   return offset;
  }
  
  const TypePtr* TypeAryPtr::with_instance_id(int instance_id) const {
    assert(is_known_instance(), "should be known");
!   return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth);
  }
  
  //=============================================================================
  
+ 
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeNarrowPtr::hash(void) const {
    return _ptrtype->hash() + 7;
  }

*** 5250,11 ***
    case KlassPtr:
    case InstKlassPtr:
    case AryKlassPtr:
    case NarrowOop:
    case NarrowKlass:
- 
    case Bottom:                  // Ye Olde Default
      return Type::BOTTOM;
    case Top:
      return this;
  
--- 5861,10 ---

*** 5334,11 ***
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeMetadataPtr::singleton(void) const {
    // detune optimizer to not generate constant metadata + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (_offset == 0) && !below_centerline(_ptr);
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeMetadataPtr::add_offset( intptr_t offset ) const {
    return make( _ptr, _metadata, xadd_offset(offset));
--- 5944,11 ---
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeMetadataPtr::singleton(void) const {
    // detune optimizer to not generate constant metadata + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (offset() == 0) && !below_centerline(_ptr);
  }
  
  //------------------------------add_offset-------------------------------------
  const TypePtr* TypeMetadataPtr::add_offset( intptr_t offset ) const {
    return make( _ptr, _metadata, xadd_offset(offset));

*** 5354,13 ***
  }
  
   //------------------------------get_con----------------------------------------
  intptr_t TypeMetadataPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert( _offset >= 0, "" );
  
!   if (_offset != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't
--- 5964,13 ---
  }
  
   //------------------------------get_con----------------------------------------
  intptr_t TypeMetadataPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert(offset() >= 0, "");
  
!   if (offset() != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't

*** 5410,11 ***
      typerr(t);
  
    case AnyPtr: {
      // Found an AnyPtr type vs self-OopPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case Null:
        if (ptr == Null)  return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
        // else fall through:
--- 6020,11 ---
      typerr(t);
  
    case AnyPtr: {
      // Found an AnyPtr type vs self-OopPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case Null:
        if (ptr == Null)  return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
        // else fall through:

*** 5438,11 ***
    case AryPtr:
      return TypePtr::BOTTOM;     // Oop meet raw is not well defined
  
    case MetadataPtr: {
      const TypeMetadataPtr *tp = t->is_metadataptr();
!     int offset = meet_offset(tp->offset());
      PTR tptr = tp->ptr();
      PTR ptr = meet_ptr(tptr);
      ciMetadata* md = (tptr == TopPTR) ? metadata() : tp->metadata();
      if (tptr == TopPTR || _ptr == TopPTR ||
          metadata()->equals(tp->metadata())) {
--- 6048,11 ---
    case AryPtr:
      return TypePtr::BOTTOM;     // Oop meet raw is not well defined
  
    case MetadataPtr: {
      const TypeMetadataPtr *tp = t->is_metadataptr();
!     Offset offset = meet_offset(tp->offset());
      PTR tptr = tp->ptr();
      PTR ptr = meet_ptr(tptr);
      ciMetadata* md = (tptr == TopPTR) ? metadata() : tp->metadata();
      if (tptr == TopPTR || _ptr == TopPTR ||
          metadata()->equals(tp->metadata())) {

*** 5482,62 ***
  
  //=============================================================================
  // Convenience common pre-built type.
  const TypeMetadataPtr *TypeMetadataPtr::BOTTOM;
  
! TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset):
    TypePtr(MetadataPtr, ptr, offset), _metadata(metadata) {
  }
  
  const TypeMetadataPtr* TypeMetadataPtr::make(ciMethod* m) {
!   return make(Constant, m, 0);
  }
  const TypeMetadataPtr* TypeMetadataPtr::make(ciMethodData* m) {
!   return make(Constant, m, 0);
  }
  
  //------------------------------make-------------------------------------------
  // Create a meta data constant
! const TypeMetadataPtr *TypeMetadataPtr::make(PTR ptr, ciMetadata* m, int offset) {
    assert(m == nullptr || !m->is_klass(), "wrong type");
    return (TypeMetadataPtr*)(new TypeMetadataPtr(ptr, m, offset))->hashcons();
  }
  
  
  const TypeKlassPtr* TypeAryPtr::as_klass_type(bool try_for_exact) const {
    const Type* elem = _ary->_elem;
    bool xk = klass_is_exact();
    if (elem->make_oopptr() != nullptr) {
      elem = elem->make_oopptr()->as_klass_type(try_for_exact);
!     if (elem->is_klassptr()->klass_is_exact()) {
!       xk = true;
      }
    }
!   return TypeAryKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, elem, klass(), 0);
  }
  
! const TypeKlassPtr* TypeKlassPtr::make(ciKlass *klass, InterfaceHandling interface_handling) {
    if (klass->is_instance_klass()) {
      return TypeInstKlassPtr::make(klass, interface_handling);
    }
    return TypeAryKlassPtr::make(klass, interface_handling);
  }
  
! const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling) {
-   if (klass->is_instance_klass()) {
-     const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
-     return TypeInstKlassPtr::make(ptr, klass, interfaces, offset);
-   }
-   return TypeAryKlassPtr::make(ptr, klass, offset, interface_handling);
- }
- 
- 
- //------------------------------TypeKlassPtr-----------------------------------
- TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset)
    : TypePtr(t, ptr, offset), _klass(klass), _interfaces(interfaces) {
    assert(klass == nullptr || !klass->is_loaded() || (klass->is_instance_klass() && !klass->is_interface()) ||
!          klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "no interface here");
  }
  
  // Is there a single ciKlass* that can represent that type?
  ciKlass* TypeKlassPtr::exact_klass_helper() const {
    assert(_klass->is_instance_klass() && !_klass->is_interface(), "No interface");
--- 6092,63 ---
  
  //=============================================================================
  // Convenience common pre-built type.
  const TypeMetadataPtr *TypeMetadataPtr::BOTTOM;
  
! TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, Offset offset):
    TypePtr(MetadataPtr, ptr, offset), _metadata(metadata) {
  }
  
  const TypeMetadataPtr* TypeMetadataPtr::make(ciMethod* m) {
!   return make(Constant, m, Offset(0));
  }
  const TypeMetadataPtr* TypeMetadataPtr::make(ciMethodData* m) {
!   return make(Constant, m, Offset(0));
  }
  
  //------------------------------make-------------------------------------------
  // Create a meta data constant
! const TypeMetadataPtr* TypeMetadataPtr::make(PTR ptr, ciMetadata* m, Offset offset) {
    assert(m == nullptr || !m->is_klass(), "wrong type");
    return (TypeMetadataPtr*)(new TypeMetadataPtr(ptr, m, offset))->hashcons();
  }
  
  
  const TypeKlassPtr* TypeAryPtr::as_klass_type(bool try_for_exact) const {
    const Type* elem = _ary->_elem;
    bool xk = klass_is_exact();
+   bool is_refined = false;
    if (elem->make_oopptr() != nullptr) {
+     is_refined = true;
      elem = elem->make_oopptr()->as_klass_type(try_for_exact);
!     if (elem->isa_aryklassptr()) {
!       const TypeAryKlassPtr* elem_klass = elem->is_aryklassptr();
+       if (elem_klass->is_refined_type()) {
+         elem = elem_klass->cast_to_non_refined();
+       }
+     } else {
+       const TypeInstKlassPtr* elem_klass = elem->is_instklassptr();
+       if (try_for_exact && !xk && elem_klass->klass_is_exact() &&
+           !elem_klass->exact_klass()->as_instance_klass()->can_be_inline_klass()) {
+         xk = true;
+       }
      }
    }
!   return TypeAryKlassPtr::make(xk ? TypePtr::Constant : TypePtr::NotNull, elem, klass(), Offset(0), is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined);
  }
  
! const TypeKlassPtr* TypeKlassPtr::make(ciKlass* klass, InterfaceHandling interface_handling) {
    if (klass->is_instance_klass()) {
      return TypeInstKlassPtr::make(klass, interface_handling);
    }
    return TypeAryKlassPtr::make(klass, interface_handling);
  }
  
! TypeKlassPtr::TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, Offset offset)
    : TypePtr(t, ptr, offset), _klass(klass), _interfaces(interfaces) {
    assert(klass == nullptr || !klass->is_loaded() || (klass->is_instance_klass() && !klass->is_interface()) ||
!          klass->is_type_array_klass() || klass->is_flat_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "no interface here");
  }
  
  // Is there a single ciKlass* that can represent that type?
  ciKlass* TypeKlassPtr::exact_klass_helper() const {
    assert(_klass->is_instance_klass() && !_klass->is_interface(), "No interface");

*** 5572,11 ***
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeKlassPtr::singleton(void) const {
    // detune optimizer to not generate constant klass + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (_offset == 0) && !below_centerline(_ptr);
  }
  
  // Do not allow interface-vs.-noninterface joins to collapse to top.
  const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculative) const {
    // logic here mirrors the one from TypeOopPtr::filter. See comments
--- 6183,11 ---
  // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
  // constants
  bool TypeKlassPtr::singleton(void) const {
    // detune optimizer to not generate constant klass + constant offset as a constant!
    // TopPTR, Null, AnyNull, Constant are all singletons
!   return (offset() == 0) && !below_centerline(_ptr);
  }
  
  // Do not allow interface-vs.-noninterface joins to collapse to top.
  const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculative) const {
    // logic here mirrors the one from TypeOopPtr::filter. See comments

*** 5602,13 ***
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypeKlassPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert( _offset >= 0, "" );
  
!   if (_offset != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't
--- 6213,13 ---
  }
  
  //------------------------------get_con----------------------------------------
  intptr_t TypeKlassPtr::get_con() const {
    assert( _ptr == Null || _ptr == Constant, "" );
!   assert( offset() >= 0, "" );
  
!   if (offset() != 0) {
      // After being ported to the compiler interface, the compiler no longer
      // directly manipulates the addresses of oops.  Rather, it only has a pointer
      // to a handle at compile time.  This handle is embedded in the generated
      // code and dereferenced at the time the nmethod is made.  Until that time,
      // it is not reasonable to do arithmetic with the addresses of oops (we don't

*** 5629,42 ***
  // Not-null object klass or below
  const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT;
  const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT_OR_NULL;
  
  bool TypeInstKlassPtr::eq(const Type *t) const {
!   const TypeKlassPtr *p = t->is_klassptr();
    return
      klass()->equals(p->klass()) &&
      TypeKlassPtr::eq(p);
  }
  
! uint TypeInstKlassPtr::hash(void) const {
!   return klass()->hash() + TypeKlassPtr::hash();
  }
  
! const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, int offset) {
    TypeInstKlassPtr *r =
!     (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, interfaces, offset))->hashcons();
  
    return r;
  }
  
  //------------------------------add_offset-------------------------------------
  // Access internals of klass object
! const TypePtr* TypeInstKlassPtr::add_offset( intptr_t offset ) const {
!   return make( _ptr, klass(), _interfaces, xadd_offset(offset) );
  }
  
  const TypeInstKlassPtr* TypeInstKlassPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, offset);
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeInstKlassPtr* TypeInstKlassPtr::cast_to_ptr_type(PTR ptr) const {
    assert(_base == InstKlassPtr, "subclass must override cast_to_ptr_type");
    if( ptr == _ptr ) return this;
!   return make(ptr, _klass, _interfaces, _offset);
  }
  
  
  bool TypeInstKlassPtr::must_be_exact() const {
    if (!_klass->is_loaded())  return false;
--- 6240,53 ---
  // Not-null object klass or below
  const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT;
  const TypeInstKlassPtr *TypeInstKlassPtr::OBJECT_OR_NULL;
  
  bool TypeInstKlassPtr::eq(const Type *t) const {
!   const TypeInstKlassPtr* p = t->is_instklassptr();
    return
      klass()->equals(p->klass()) &&
+     _flat_in_array == p->_flat_in_array &&
      TypeKlassPtr::eq(p);
  }
  
! uint TypeInstKlassPtr::hash() const {
!   return klass()->hash() + TypeKlassPtr::hash() + static_cast<uint>(_flat_in_array);
  }
  
! const TypeInstKlassPtr *TypeInstKlassPtr::make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, Offset offset, FlatInArray flat_in_array) {
+   if (flat_in_array == Uninitialized) {
+     flat_in_array = compute_flat_in_array(k->as_instance_klass(), ptr == Constant);
+   }
    TypeInstKlassPtr *r =
!     (TypeInstKlassPtr*)(new TypeInstKlassPtr(ptr, k, interfaces, offset, flat_in_array))->hashcons();
  
    return r;
  }
  
+ bool TypeInstKlassPtr::empty() const {
+   if (_flat_in_array == TopFlat) {
+     return true;
+   }
+   return TypeKlassPtr::empty();
+ }
+ 
  //------------------------------add_offset-------------------------------------
  // Access internals of klass object
! const TypePtr *TypeInstKlassPtr::add_offset( intptr_t offset ) const {
!   return make(_ptr, klass(), _interfaces, xadd_offset(offset), _flat_in_array);
  }
  
  const TypeInstKlassPtr* TypeInstKlassPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, klass(), _interfaces, Offset(offset), _flat_in_array);
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeInstKlassPtr* TypeInstKlassPtr::cast_to_ptr_type(PTR ptr) const {
    assert(_base == InstKlassPtr, "subclass must override cast_to_ptr_type");
    if( ptr == _ptr ) return this;
!   return make(ptr, _klass, _interfaces, _offset, _flat_in_array);
  }
  
  
  bool TypeInstKlassPtr::must_be_exact() const {
    if (!_klass->is_loaded())  return false;

*** 5676,11 ***
  //-----------------------------cast_to_exactness-------------------------------
  const TypeKlassPtr* TypeInstKlassPtr::cast_to_exactness(bool klass_is_exact) const {
    if (klass_is_exact == (_ptr == Constant)) return this;
    if (must_be_exact()) return this;
    ciKlass* k = klass();
!   return make(klass_is_exact ? Constant : NotNull, k, _interfaces, _offset);
  }
  
  
  //-----------------------------as_instance_type--------------------------------
  // Corresponding type for an instance of the given class.
--- 6298,12 ---
  //-----------------------------cast_to_exactness-------------------------------
  const TypeKlassPtr* TypeInstKlassPtr::cast_to_exactness(bool klass_is_exact) const {
    if (klass_is_exact == (_ptr == Constant)) return this;
    if (must_be_exact()) return this;
    ciKlass* k = klass();
!   FlatInArray flat_in_array = compute_flat_in_array(k->as_instance_klass(), klass_is_exact);
+   return make(klass_is_exact ? Constant : NotNull, k, _interfaces, _offset, flat_in_array);
  }
  
  
  //-----------------------------as_instance_type--------------------------------
  // Corresponding type for an instance of the given class.

*** 5692,13 ***
    Dependencies* deps = C->dependencies();
    assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
    // Element is an instance
    bool klass_is_exact = false;
    const TypeInterfaces* interfaces = _interfaces;
    if (k->is_loaded()) {
      // Try to set klass_is_exact.
-     ciInstanceKlass* ik = k->as_instance_klass();
      klass_is_exact = ik->is_final();
      if (!klass_is_exact && klass_change
          && deps != nullptr && UseUniqueSubclasses) {
        ciInstanceKlass* sub = ik->unique_concrete_subklass();
        if (sub != nullptr) {
--- 6315,13 ---
    Dependencies* deps = C->dependencies();
    assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
    // Element is an instance
    bool klass_is_exact = false;
    const TypeInterfaces* interfaces = _interfaces;
+   ciInstanceKlass* ik = k->as_instance_klass();
    if (k->is_loaded()) {
      // Try to set klass_is_exact.
      klass_is_exact = ik->is_final();
      if (!klass_is_exact && klass_change
          && deps != nullptr && UseUniqueSubclasses) {
        ciInstanceKlass* sub = ik->unique_concrete_subklass();
        if (sub != nullptr) {

*** 5708,11 ***
            xk = sub->is_final();
          }
        }
      }
    }
!   return TypeInstPtr::make(TypePtr::BotPTR, k, interfaces, xk, nullptr, 0);
  }
  
  //------------------------------xmeet------------------------------------------
  // Compute the MEET of two types, return a new Type object.
  const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {
--- 6331,13 ---
            xk = sub->is_final();
          }
        }
      }
    }
! 
+   FlatInArray flat_in_array = compute_flat_in_array_if_unknown(ik, xk, _flat_in_array);
+   return TypeInstPtr::make(TypePtr::BotPTR, k, interfaces, xk, nullptr, Offset(0), flat_in_array);
  }
  
  //------------------------------xmeet------------------------------------------
  // Compute the MEET of two types, return a new Type object.
  const Type    *TypeInstKlassPtr::xmeet( const Type *t ) const {

*** 5744,19 ***
      typerr(t);
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-KlassPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
        return this;
      case Null:
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      case AnyNull:
!       return make( ptr, klass(), _interfaces, offset );
      case BotPTR:
      case NotNull:
        return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      default: typerr(t);
      }
--- 6369,19 ---
      typerr(t);
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-KlassPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
        return this;
      case Null:
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      case AnyNull:
!       return make(ptr, klass(), _interfaces, offset, _flat_in_array);
      case BotPTR:
      case NotNull:
        return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      default: typerr(t);
      }

*** 5765,11 ***
    case RawPtr:
    case MetadataPtr:
    case OopPtr:
    case AryPtr:                  // Meet with AryPtr
    case InstPtr:                 // Meet with InstPtr
!     return TypePtr::BOTTOM;
  
    //
    //             A-top         }
    //           /   |   \       }  Tops
    //       B-top A-any C-top   }
--- 6390,11 ---
    case RawPtr:
    case MetadataPtr:
    case OopPtr:
    case AryPtr:                  // Meet with AryPtr
    case InstPtr:                 // Meet with InstPtr
!       return TypePtr::BOTTOM;
  
    //
    //             A-top         }
    //           /   |   \       }  Tops
    //       B-top A-any C-top   }

*** 5785,34 ***
    //             A-bot         }
    //
  
    case InstKlassPtr: {  // Meet two KlassPtr types
      const TypeInstKlassPtr *tkls = t->is_instklassptr();
!     int  off     = meet_offset(tkls->offset());
      PTR  ptr     = meet_ptr(tkls->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tkls);
  
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
!     switch(meet_instptr(ptr, interfaces, this, tkls, res_klass, res_xk)) {
        case UNLOADED:
          ShouldNotReachHere();
        case SUBTYPE:
        case NOT_SUBTYPE:
        case LCA:
        case QUICK: {
          assert(res_xk == (ptr == Constant), "");
!         const Type* res = make(ptr, res_klass, interfaces, off);
          return res;
        }
        default:
          ShouldNotReachHere();
      }
    } // End of case KlassPtr
    case AryKlassPtr: {                // All arrays inherit from Object class
      const TypeAryKlassPtr *tp = t->is_aryklassptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tp);
      const TypeInterfaces* tp_interfaces = tp->_interfaces;
      const TypeInterfaces* this_interfaces = _interfaces;
  
--- 6410,35 ---
    //             A-bot         }
    //
  
    case InstKlassPtr: {  // Meet two KlassPtr types
      const TypeInstKlassPtr *tkls = t->is_instklassptr();
!     Offset  off     = meet_offset(tkls->offset());
      PTR  ptr     = meet_ptr(tkls->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tkls);
  
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
!     const FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, tkls->flat_in_array());
+     switch (meet_instptr(ptr, interfaces, this, tkls, res_klass, res_xk)) {
        case UNLOADED:
          ShouldNotReachHere();
        case SUBTYPE:
        case NOT_SUBTYPE:
        case LCA:
        case QUICK: {
          assert(res_xk == (ptr == Constant), "");
!         const Type* res = make(ptr, res_klass, interfaces, off, flat_in_array);
          return res;
        }
        default:
          ShouldNotReachHere();
      }
    } // End of case KlassPtr
    case AryKlassPtr: {                // All arrays inherit from Object class
      const TypeAryKlassPtr *tp = t->is_aryklassptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tp);
      const TypeInterfaces* tp_interfaces = tp->_interfaces;
      const TypeInterfaces* this_interfaces = _interfaces;
  

*** 5820,52 ***
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
!       if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && !klass_is_exact()) {
!         return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset);
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          interfaces = _interfaces->intersection_with(tp->_interfaces);
!         return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
        }
      case Constant:
      case NotNull:
!     case BotPTR:                // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull )
          // If 'this' (InstPtr) is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
!         if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) && !klass_is_exact()) {
            // that is, tp's array type is a subtype of my klass
!           return TypeAryKlassPtr::make(ptr,
-                                        tp->elem(), tp->klass(), offset);
          }
        }
        // The other case cannot happen, since I cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if( ptr == Constant )
!          ptr = NotNull;
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
      default: typerr(t);
      }
    }
  
    } // End of switch
    return this;                  // Return the double constant
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
! const Type    *TypeInstKlassPtr::xdual() const {
!   return new TypeInstKlassPtr(dual_ptr(), klass(), _interfaces, dual_offset());
  }
  
  template <class T1, class T2> bool TypePtr::is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
    static_assert(std::is_base_of<T2, T1>::value, "");
    if (!this_one->is_loaded() || !other->is_loaded()) {
--- 6446,60 ---
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
!       //
!       // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper().
+       if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) &&
+           !klass_is_exact() && !is_not_flat_in_array()) {
+         return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset, tp->is_not_flat(), tp->is_not_null_free(), tp->is_flat(), tp->is_null_free(), tp->is_atomic(), tp->is_refined_type());
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          interfaces = _interfaces->intersection_with(tp->_interfaces);
!         FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, NotFlat);
+         return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array);
        }
      case Constant:
      case NotNull:
!     case BotPTR: { // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if( above_centerline(_ptr) ) { // if( _ptr == TopPTR || _ptr == AnyNull )
          // If 'this' (InstPtr) is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
!         //
+         // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper().
+         if (klass()->equals(ciEnv::current()->Object_klass()) && tp_interfaces->contains(this_interfaces) &&
+             !klass_is_exact() && !is_not_flat_in_array()) {
            // that is, tp's array type is a subtype of my klass
!           return TypeAryKlassPtr::make(ptr, tp->elem(), tp->klass(), offset, tp->is_not_flat(), tp->is_not_null_free(), tp->is_flat(), tp->is_null_free(), tp->is_atomic(), tp->is_refined_type());
          }
        }
        // The other case cannot happen, since I cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if( ptr == Constant )
!         ptr = NotNull;
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       FlatInArray flat_in_array = meet_flat_in_array(_flat_in_array, NotFlat);
+       return make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array);
+     }
      default: typerr(t);
      }
    }
  
    } // End of switch
    return this;                  // Return the double constant
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
! const Type* TypeInstKlassPtr::xdual() const {
!   return new TypeInstKlassPtr(dual_ptr(), klass(), _interfaces, dual_offset(), dual_flat_in_array());
  }
  
  template <class T1, class T2> bool TypePtr::is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact) {
    static_assert(std::is_base_of<T2, T1>::value, "");
    if (!this_one->is_loaded() || !other->is_loaded()) {

*** 5955,77 ***
    }
    ciKlass* k = klass();
    Compile* C = Compile::current();
    Dependencies* deps = C->dependencies();
    assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
-   const TypeInterfaces* interfaces = _interfaces;
    if (k->is_loaded()) {
      ciInstanceKlass* ik = k->as_instance_klass();
!     bool klass_is_exact = ik->is_final();
-     if (!klass_is_exact &&
-         deps != nullptr) {
        ciInstanceKlass* sub = ik->unique_concrete_subklass();
        if (sub != nullptr) {
!         if (_interfaces->eq(sub)) {
            deps->assert_abstract_with_unique_concrete_subtype(ik, sub);
!           k = ik = sub;
-           klass_is_exact = sub->is_final();
-           return TypeKlassPtr::make(klass_is_exact ? Constant : _ptr, k, _offset);
          }
        }
      }
    }
    return this;
  }
  
  #ifndef PRODUCT
  void TypeInstKlassPtr::dump2(Dict& d, uint depth, outputStream* st) const {
    st->print("instklassptr:");
    klass()->print_name_on(st);
    _interfaces->dump(st);
    st->print(":%s", ptr_msg[_ptr]);
    dump_offset(st);
  }
  #endif // PRODUCT
  
! const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* k, int offset) {
!   return (TypeAryKlassPtr*)(new TypeAryKlassPtr(ptr, elem, k, offset))->hashcons();
  }
  
! const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, ciKlass* k, int offset, InterfaceHandling interface_handling) {
    if (k->is_obj_array_klass()) {
      // Element is an object array. Recursively call ourself.
      ciKlass* eklass = k->as_obj_array_klass()->element_klass();
!     const TypeKlassPtr *etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false);
!     return TypeAryKlassPtr::make(ptr, etype, nullptr, offset);
    } else if (k->is_type_array_klass()) {
      // Element is an typeArray
!     const Type* etype = get_const_basic_type(k->as_type_array_klass()->element_type());
!     return TypeAryKlassPtr::make(ptr, etype, k, offset);
    } else {
      ShouldNotReachHere();
-     return nullptr;
    }
  }
  
  const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass, InterfaceHandling interface_handling) {
!   return TypeAryKlassPtr::make(Constant, klass, 0, interface_handling);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAryKlassPtr::eq(const Type *t) const {
    const TypeAryKlassPtr *p = t->is_aryklassptr();
    return
      _elem == p->_elem &&  // Check array
      TypeKlassPtr::eq(p);  // Check sub-parts
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAryKlassPtr::hash(void) const {
!   return (uint)(uintptr_t)_elem + TypeKlassPtr::hash();
  }
  
  //----------------------compute_klass------------------------------------------
  // Compute the defining klass for this class
  ciKlass* TypeAryPtr::compute_klass() const {
--- 6589,130 ---
    }
    ciKlass* k = klass();
    Compile* C = Compile::current();
    Dependencies* deps = C->dependencies();
    assert((deps != nullptr) == (C->method() != nullptr && C->method()->code_size() > 0), "sanity");
    if (k->is_loaded()) {
      ciInstanceKlass* ik = k->as_instance_klass();
!     if (deps != nullptr) {
        ciInstanceKlass* sub = ik->unique_concrete_subklass();
        if (sub != nullptr) {
!         bool improve_to_exact = sub->is_final() && _ptr == NotNull;
+         const TypeInstKlassPtr* improved = TypeInstKlassPtr::make(improve_to_exact ? Constant : _ptr, sub, _offset);
+         if (improved->_interfaces->contains(_interfaces)) {
            deps->assert_abstract_with_unique_concrete_subtype(ik, sub);
!           return improved;
          }
        }
      }
    }
    return this;
  }
  
+ bool TypeInstKlassPtr::can_be_inline_array() const {
+   return _klass->equals(ciEnv::current()->Object_klass()) && TypeAryKlassPtr::_array_interfaces->contains(_interfaces);
+ }
+ 
  #ifndef PRODUCT
  void TypeInstKlassPtr::dump2(Dict& d, uint depth, outputStream* st) const {
    st->print("instklassptr:");
    klass()->print_name_on(st);
    _interfaces->dump(st);
    st->print(":%s", ptr_msg[_ptr]);
    dump_offset(st);
+   dump_flat_in_array(_flat_in_array, st);
  }
  #endif // PRODUCT
  
! bool TypeAryKlassPtr::can_be_inline_array() const {
!   return _elem->isa_instklassptr() && _elem->is_instklassptr()->_klass->can_be_inline_klass();
+ }
+ 
+ bool TypeInstPtr::can_be_inline_array() const {
+   return _klass->equals(ciEnv::current()->Object_klass()) && TypeAryPtr::_array_interfaces->contains(_interfaces);
  }
  
! bool TypeAryPtr::can_be_inline_array() const {
+   return elem()->make_ptr() && elem()->make_ptr()->isa_instptr() && elem()->make_ptr()->is_instptr()->_klass->can_be_inline_klass();
+ }
+ 
+ const TypeAryKlassPtr *TypeAryKlassPtr::make(PTR ptr, const Type* elem, ciKlass* k, Offset offset, bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined_type) {
+   return (TypeAryKlassPtr*)(new TypeAryKlassPtr(ptr, elem, k, offset, not_flat, not_null_free, flat, null_free, atomic, refined_type))->hashcons();
+ }
+ 
+ const TypeAryKlassPtr* TypeAryKlassPtr::make(PTR ptr, ciKlass* k, Offset offset, InterfaceHandling interface_handling, bool not_flat, bool not_null_free, bool flat, bool null_free, bool atomic, bool refined_type) {
+   const Type* etype;
    if (k->is_obj_array_klass()) {
      // Element is an object array. Recursively call ourself.
      ciKlass* eklass = k->as_obj_array_klass()->element_klass();
!     etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false);
!     k = nullptr;
    } else if (k->is_type_array_klass()) {
      // Element is an typeArray
!     etype = get_const_basic_type(k->as_type_array_klass()->element_type());
!   } else if (k->is_flat_array_klass()) {
+     ciKlass* eklass = k->as_flat_array_klass()->element_klass();
+     etype = TypeKlassPtr::make(eklass, interface_handling)->cast_to_exactness(false);
+     k = nullptr;
    } else {
      ShouldNotReachHere();
    }
+ 
+   return TypeAryKlassPtr::make(ptr, etype, k, offset, not_flat, not_null_free, flat, null_free, atomic, refined_type);
  }
  
  const TypeAryKlassPtr* TypeAryKlassPtr::make(ciKlass* klass, InterfaceHandling interface_handling) {
!   ciArrayKlass* k = klass->as_array_klass();
+   if (k->is_refined()) {
+     return TypeAryKlassPtr::make(Constant, k, Offset(0), interface_handling, !k->is_flat_array_klass(), !k->is_elem_null_free(),
+                                  k->is_flat_array_klass(), k->is_elem_null_free(), k->is_elem_atomic(), true);
+   } else {
+     // Use the default combination to canonicalize all non-refined klass pointers
+     return TypeAryKlassPtr::make(Constant, k, Offset(0), interface_handling, true, true, false, false, true, false);
+   }
+ }
+ 
+ const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_non_refined() const {
+   assert(is_refined_type(), "must be a refined type");
+   PTR ptr = _ptr;
+   // There can be multiple refined array types corresponding to a single unrefined type
+   if (ptr == NotNull && elem()->is_klassptr()->klass_is_exact()) {
+     ptr = Constant;
+   }
+   return make(ptr, elem(), nullptr, _offset, true, true, false, false, true, false);
+ }
+ 
+ // Get the (non-)refined array klass ptr
+ const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_refined_array_klass_ptr(bool refined) const {
+   if ((refined == is_refined_type()) || !klass_is_exact() || (!exact_klass()->is_obj_array_klass() && !exact_klass()->is_flat_array_klass())) {
+     return this;
+   }
+   ciArrayKlass* k = exact_klass()->as_array_klass();
+   k = ciObjArrayKlass::make(k->element_klass(), refined);
+   return make(k, trust_interfaces);
  }
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeAryKlassPtr::eq(const Type *t) const {
    const TypeAryKlassPtr *p = t->is_aryklassptr();
    return
      _elem == p->_elem &&  // Check array
+     _flat == p->_flat &&
+     _not_flat == p->_not_flat &&
+     _null_free == p->_null_free &&
+     _not_null_free == p->_not_null_free &&
+     _atomic == p->_atomic &&
+     _refined_type == p->_refined_type &&
      TypeKlassPtr::eq(p);  // Check sub-parts
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeAryKlassPtr::hash(void) const {
!   return (uint)(uintptr_t)_elem + TypeKlassPtr::hash() + (uint)(_not_flat ? 43 : 0) +
+       (uint)(_not_null_free ? 44 : 0) + (uint)(_flat ? 45 : 0) + (uint)(_null_free ? 46 : 0)  + (uint)(_atomic ? 47 : 0) + (uint)(_refined_type ? 48 : 0);
  }
  
  //----------------------compute_klass------------------------------------------
  // Compute the defining klass for this class
  ciKlass* TypeAryPtr::compute_klass() const {

*** 6038,13 ***
      el = el->make_ptr();
    }
  
    // Get element klass
    if ((tinst = el->isa_instptr()) != nullptr) {
!     // Leave k_ary at null.
    } else if ((tary = el->isa_aryptr()) != nullptr) {
!     // Leave k_ary at null.
    } else if ((el->base() == Type::Top) ||
               (el->base() == Type::Bottom)) {
      // element type of Bottom occurs from meet of basic type
      // and object; Top occurs when doing join on Bottom.
      // Leave k_ary at null.
--- 6725,13 ---
      el = el->make_ptr();
    }
  
    // Get element klass
    if ((tinst = el->isa_instptr()) != nullptr) {
!     // Leave k_ary at nullptr.
    } else if ((tary = el->isa_aryptr()) != nullptr) {
!     // Leave k_ary at nullptr.
    } else if ((el->base() == Type::Top) ||
               (el->base() == Type::Bottom)) {
      // element type of Bottom occurs from meet of basic type
      // and object; Top occurs when doing join on Bottom.
      // Leave k_ary at null.

*** 6088,12 ***
    if (_ary->_elem->make_ptr() && _ary->_elem->make_ptr()->isa_oopptr()) {
      ciKlass* k = _ary->_elem->make_ptr()->is_oopptr()->exact_klass_helper();
      if (k == nullptr) {
        return nullptr;
      }
!     k = ciObjArrayKlass::make(k);
!     return k;
    }
  
    return klass();
  }
  
--- 6775,20 ---
    if (_ary->_elem->make_ptr() && _ary->_elem->make_ptr()->isa_oopptr()) {
      ciKlass* k = _ary->_elem->make_ptr()->is_oopptr()->exact_klass_helper();
      if (k == nullptr) {
        return nullptr;
      }
!     if (k->is_array_klass() && k->as_array_klass()->is_refined()) {
!       // We have no mechanism to create an array of refined arrays
+       k = ciObjArrayKlass::make(k->as_array_klass()->element_klass(), false);
+     }
+     if (klass_is_exact()) {
+       return ciObjArrayKlass::make(k, true, is_null_free(), is_atomic());
+     } else {
+       // We may reach here if called recursively, must be an unrefined type then
+       return ciObjArrayKlass::make(k, false);
+     }
    }
  
    return klass();
  }
  

*** 6108,44 ***
  }
  
  //------------------------------add_offset-------------------------------------
  // Access internals of klass object
  const TypePtr* TypeAryKlassPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, elem(), klass(), xadd_offset(offset));
  }
  
  const TypeAryKlassPtr* TypeAryKlassPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, elem(), klass(), offset);
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_ptr_type(PTR ptr) const {
    assert(_base == AryKlassPtr, "subclass must override cast_to_ptr_type");
    if (ptr == _ptr) return this;
!   return make(ptr, elem(), _klass, _offset);
  }
  
  bool TypeAryKlassPtr::must_be_exact() const {
!   if (_elem == Type::BOTTOM) return false;
!   if (_elem == Type::TOP   ) return false;
!   const TypeKlassPtr*  tk = _elem->isa_klassptr();
!   if (!tk)             return true;   // a primitive type, like int
!   return tk->must_be_exact();
! }
  
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeKlassPtr *TypeAryKlassPtr::cast_to_exactness(bool klass_is_exact) const {
!   if (must_be_exact()) return this;  // cannot clear xk
!   ciKlass* k = _klass;
    const Type* elem = this->elem();
    if (elem->isa_klassptr() && !klass_is_exact) {
      elem = elem->is_klassptr()->cast_to_exactness(klass_is_exact);
    }
-   return make(klass_is_exact ? Constant : NotNull, elem, k, _offset);
- }
  
  
  //-----------------------------as_instance_type--------------------------------
  // Corresponding type for an instance of the given class.
  // It will be NotNull, and exact if and only if the klass type is exact.
  const TypeOopPtr* TypeAryKlassPtr::as_instance_type(bool klass_change) const {
--- 6803,67 ---
  }
  
  //------------------------------add_offset-------------------------------------
  // Access internals of klass object
  const TypePtr* TypeAryKlassPtr::add_offset(intptr_t offset) const {
!   return make(_ptr, elem(), klass(), xadd_offset(offset), is_not_flat(), is_not_null_free(), _flat, _null_free, _atomic, _refined_type);
  }
  
  const TypeAryKlassPtr* TypeAryKlassPtr::with_offset(intptr_t offset) const {
!   return make(_ptr, elem(), klass(), Offset(offset), is_not_flat(), is_not_null_free(), _flat, _null_free, _atomic, _refined_type);
  }
  
  //------------------------------cast_to_ptr_type-------------------------------
  const TypeAryKlassPtr* TypeAryKlassPtr::cast_to_ptr_type(PTR ptr) const {
    assert(_base == AryKlassPtr, "subclass must override cast_to_ptr_type");
    if (ptr == _ptr) return this;
!   return make(ptr, elem(), _klass, _offset, is_not_flat(), is_not_null_free(), _flat, _null_free, _atomic, _refined_type);
  }
  
  bool TypeAryKlassPtr::must_be_exact() const {
!   assert(klass_is_exact(), "precondition");
!   if (_elem == Type::BOTTOM || _elem == Type::TOP) {
!     return false;
!   }
!   const TypeKlassPtr* elem = _elem->isa_klassptr();
!   if (elem == nullptr) {
+     // primitive arrays
+     return true;
+   }
  
+   // refined types are final
+   return _refined_type;
+ }
  
  //-----------------------------cast_to_exactness-------------------------------
  const TypeKlassPtr *TypeAryKlassPtr::cast_to_exactness(bool klass_is_exact) const {
!   if (klass_is_exact == this->klass_is_exact()) {
!     return this;
+   }
+   if (!klass_is_exact && must_be_exact()) {
+     return this;
+   }
    const Type* elem = this->elem();
    if (elem->isa_klassptr() && !klass_is_exact) {
      elem = elem->is_klassptr()->cast_to_exactness(klass_is_exact);
    }
  
+   if (klass_is_exact) {
+     // cast_to_exactness(true) really means get the LCA of all values represented by this
+     // TypeAryKlassPtr. As a result, it must be an unrefined klass pointer.
+     return make(Constant, elem, nullptr, _offset, true, true, false, false, true, false);
+   } else {
+     // cast_to_exactness(false) means get the TypeAryKlassPtr representing all values that subtype
+     // this value
+     bool not_inline = !_elem->isa_instklassptr() || !_elem->is_instklassptr()->instance_klass()->can_be_inline_klass();
+     bool not_flat = !UseArrayFlattening || not_inline ||
+                     (_elem->isa_instklassptr() && _elem->is_instklassptr()->instance_klass()->is_inlinetype() && !_elem->is_instklassptr()->instance_klass()->maybe_flat_in_array());
+     bool not_null_free = not_inline;
+     bool atomic = not_flat;
+     return make(NotNull, elem, nullptr, _offset, not_flat, not_null_free, false, false, atomic, false);
+   }
+ }
  
  //-----------------------------as_instance_type--------------------------------
  // Corresponding type for an instance of the given class.
  // It will be NotNull, and exact if and only if the klass type is exact.
  const TypeOopPtr* TypeAryKlassPtr::as_instance_type(bool klass_change) const {

*** 6156,11 ***
      el = elem()->is_klassptr()->as_instance_type(false)->cast_to_exactness(false);
      k = nullptr;
    } else {
      el = elem();
    }
!   return TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(el, TypeInt::POS), k, xk, 0);
  }
  
  
  //------------------------------xmeet------------------------------------------
  // Compute the MEET of two types, return a new Type object.
--- 6874,15 ---
      el = elem()->is_klassptr()->as_instance_type(false)->cast_to_exactness(false);
      k = nullptr;
    } else {
      el = elem();
    }
!   bool null_free = _null_free;
+   if (null_free && el->isa_ptr()) {
+     el = el->is_ptr()->join_speculative(TypePtr::NOTNULL);
+   }
+   return TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(el, TypeInt::POS, false, is_flat(), is_not_flat(), is_not_null_free(), is_atomic()), k, xk, Offset(0));
  }
  
  
  //------------------------------xmeet------------------------------------------
  // Compute the MEET of two types, return a new Type object.

*** 6193,19 ***
      typerr(t);
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-KlassPtr type
      const TypePtr *tp = t->is_ptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
        return this;
      case Null:
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      case AnyNull:
!       return make( ptr, _elem, klass(), offset );
      case BotPTR:
      case NotNull:
        return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      default: typerr(t);
      }
--- 6915,19 ---
      typerr(t);
  
    case AnyPtr: {                // Meeting to AnyPtrs
      // Found an AnyPtr type vs self-KlassPtr type
      const TypePtr *tp = t->is_ptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      switch (tp->ptr()) {
      case TopPTR:
        return this;
      case Null:
        if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      case AnyNull:
!       return make(ptr, _elem, klass(), offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type());
      case BotPTR:
      case NotNull:
        return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
      default: typerr(t);
      }

*** 6234,23 ***
    //             A-bot         }
    //
  
    case AryKlassPtr: {  // Meet two KlassPtr types
      const TypeAryKlassPtr *tap = t->is_aryklassptr();
!     int off = meet_offset(tap->offset());
      const Type* elem = _elem->meet(tap->_elem);
- 
      PTR ptr = meet_ptr(tap->ptr());
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
!     meet_aryptr(ptr, elem, this, tap, res_klass, res_xk);
      assert(res_xk == (ptr == Constant), "");
!     return make(ptr, elem, res_klass, off);
    } // End of case KlassPtr
    case InstKlassPtr: {
      const TypeInstKlassPtr *tp = t->is_instklassptr();
!     int offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tp);
      const TypeInterfaces* tp_interfaces = tp->_interfaces;
      const TypeInterfaces* this_interfaces = _interfaces;
  
--- 6956,59 ---
    //             A-bot         }
    //
  
    case AryKlassPtr: {  // Meet two KlassPtr types
      const TypeAryKlassPtr *tap = t->is_aryklassptr();
!     Offset off = meet_offset(tap->offset());
      const Type* elem = _elem->meet(tap->_elem);
      PTR ptr = meet_ptr(tap->ptr());
      ciKlass* res_klass = nullptr;
      bool res_xk = false;
!     bool res_flat = false;
+     bool res_not_flat = false;
+     bool res_not_null_free = false;
+     bool res_atomic = false;
+     MeetResult res = meet_aryptr(ptr, elem, this, tap,
+                                  res_klass, res_xk, res_flat, res_not_flat, res_not_null_free, res_atomic);
      assert(res_xk == (ptr == Constant), "");
!     bool flat = meet_flat(tap->_flat);
+     bool null_free = meet_null_free(tap->_null_free);
+     bool atomic = meet_atomic(tap->_atomic);
+     bool refined_type = _refined_type && tap->_refined_type;
+     if (res == NOT_SUBTYPE) {
+       flat = false;
+       null_free = false;
+       atomic = false;
+       refined_type = false;
+     } else if (res == SUBTYPE) {
+       if (above_centerline(tap->ptr()) && !above_centerline(this->ptr())) {
+         flat = _flat;
+         null_free = _null_free;
+         atomic = _atomic;
+         refined_type = _refined_type;
+       } else if (above_centerline(this->ptr()) && !above_centerline(tap->ptr())) {
+         flat = tap->_flat;
+         null_free = tap->_null_free;
+         atomic = tap->_atomic;
+         refined_type = tap->_refined_type;
+       } else if (above_centerline(this->ptr()) && above_centerline(tap->ptr())) {
+         flat = _flat || tap->_flat;
+         null_free = _null_free || tap->_null_free;
+         atomic = _atomic || tap->_atomic;
+         refined_type = _refined_type || tap->_refined_type;
+       } else if (res_xk && _refined_type != tap->_refined_type) {
+         // This can happen if the phi emitted by LibraryCallKit::load_default_refined_array_klass/load_non_refined_array_klass
+         // is processed before the typeArray guard is folded. Both inputs are constant but the input corresponding to the
+         // typeArray will go away. Don't constant fold it yet but wait for the control input to collapse.
+         ptr = PTR::NotNull;
+       }
+     }
+     return make(ptr, elem, res_klass, off, res_not_flat, res_not_null_free, flat, null_free, atomic, refined_type);
    } // End of case KlassPtr
    case InstKlassPtr: {
      const TypeInstKlassPtr *tp = t->is_instklassptr();
!     Offset offset = meet_offset(tp->offset());
      PTR ptr = meet_ptr(tp->ptr());
      const TypeInterfaces* interfaces = meet_interfaces(tp);
      const TypeInterfaces* tp_interfaces = tp->_interfaces;
      const TypeInterfaces* this_interfaces = _interfaces;
  

*** 6258,41 ***
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
!           !tp->klass_is_exact()) {
!         return TypeAryKlassPtr::make(ptr, _elem, _klass, offset);
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          interfaces = this_interfaces->intersection_with(tp->_interfaces);
!         return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
        }
      case Constant:
      case NotNull:
!     case BotPTR:                // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if (above_centerline(tp->ptr())) {
          // If 'tp'  is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
          if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
!             !tp->klass_is_exact()) {
            // that is, my array type is a subtype of 'tp' klass
!           return make(ptr, _elem, _klass, offset);
          }
        }
        // The other case cannot happen, since t cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if (ptr == Constant)
!          ptr = NotNull;
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset);
      default: typerr(t);
      }
    }
  
    } // End of switch
--- 7016,48 ---
      case TopPTR:
      case AnyNull:                // Fall 'down' to dual of object klass
        // For instances when a subclass meets a superclass we fall
        // below the centerline when the superclass is exact. We need to
        // do the same here.
+       //
+       // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper().
        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
!           !tp->klass_is_exact() && !tp->is_not_flat_in_array()) {
!         return TypeAryKlassPtr::make(ptr, _elem, _klass, offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type());
        } else {
          // cannot subclass, so the meet has to fall badly below the centerline
          ptr = NotNull;
          interfaces = this_interfaces->intersection_with(tp->_interfaces);
!         FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array());
+         return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, flat_in_array);
        }
      case Constant:
      case NotNull:
!     case BotPTR: { // Fall down to object klass
        // LCA is object_klass, but if we subclass from the top we can do better
        if (above_centerline(tp->ptr())) {
          // If 'tp'  is above the centerline and it is Object class
          // then we can subclass in the Java class hierarchy.
          // For instances when a subclass meets a superclass we fall
          // below the centerline when the superclass is exact. We need
          // to do the same here.
+         //
+         // Flat in array: See explanation for meet with TypeInstPtr in TypeAryPtr::xmeet_helper().
          if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) &&
!             !tp->klass_is_exact() && !tp->is_not_flat_in_array()) {
            // that is, my array type is a subtype of 'tp' klass
!           return make(ptr, _elem, _klass, offset, is_not_flat(), is_not_null_free(), is_flat(), is_null_free(), is_atomic(), is_refined_type());
          }
        }
        // The other case cannot happen, since t cannot be a subtype of an array.
        // The meet falls down to Object class below centerline.
        if (ptr == Constant)
!         ptr = NotNull;
        interfaces = this_interfaces->intersection_with(tp_interfaces);
!       FlatInArray flat_in_array = meet_flat_in_array(NotFlat, tp->flat_in_array());
+       return TypeInstKlassPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, offset, tp->flat_in_array());
+     }
      default: typerr(t);
      }
    }
  
    } // End of switch

*** 6326,10 ***
--- 7091,13 ---
    }
  
    const TypePtr* other_elem = other_ary->elem()->make_ptr();
    const TypePtr* this_elem = this_one->elem()->make_ptr();
    if (this_elem != nullptr && other_elem != nullptr) {
+     if (other->is_null_free() && !this_one->is_null_free()) {
+       return false; // A nullable array can't be a subtype of a null-free array
+     }
      return this_one->is_reference_type(this_elem)->is_java_subtype_of_helper(this_one->is_reference_type(other_elem), this_exact, other_exact);
    }
    if (this_elem == nullptr && other_elem == nullptr) {
      return this_one->klass()->is_subtype_of(other->klass());
    }

*** 6418,21 ***
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type    *TypeAryKlassPtr::xdual() const {
!   return new TypeAryKlassPtr(dual_ptr(), elem()->dual(), klass(), dual_offset());
  }
  
  // Is there a single ciKlass* that can represent that type?
  ciKlass* TypeAryKlassPtr::exact_klass_helper() const {
    if (elem()->isa_klassptr()) {
      ciKlass* k = elem()->is_klassptr()->exact_klass_helper();
      if (k == nullptr) {
        return nullptr;
      }
!     k = ciObjArrayKlass::make(k);
      return k;
    }
  
    return klass();
  }
--- 7186,22 ---
  }
  
  //------------------------------xdual------------------------------------------
  // Dual: compute field-by-field dual
  const Type    *TypeAryKlassPtr::xdual() const {
!   return new TypeAryKlassPtr(dual_ptr(), elem()->dual(), klass(), dual_offset(), !is_not_flat(), !is_not_null_free(), dual_flat(), dual_null_free(), dual_atomic(), _refined_type);
  }
  
  // Is there a single ciKlass* that can represent that type?
  ciKlass* TypeAryKlassPtr::exact_klass_helper() const {
    if (elem()->isa_klassptr()) {
      ciKlass* k = elem()->is_klassptr()->exact_klass_helper();
      if (k == nullptr) {
        return nullptr;
      }
!     assert(!k->is_array_klass() || !k->as_array_klass()->is_refined(), "no mechanism to create an array of refined arrays %s", k->name()->as_utf8());
+     k = ciArrayKlass::make(k, is_null_free(), is_atomic(), _refined_type);
      return k;
    }
  
    return klass();
  }

*** 6459,10 ***
--- 7228,18 ---
  void TypeAryKlassPtr::dump2( Dict & d, uint depth, outputStream *st ) const {
    st->print("aryklassptr:[");
    _elem->dump2(d, depth, st);
    _interfaces->dump(st);
    st->print(":%s", ptr_msg[_ptr]);
+   if (_flat) st->print(":flat");
+   if (_null_free) st->print(":null free");
+   if (_atomic) st->print(":atomic");
+   if (_refined_type) st->print(":refined_type");
+   if (Verbose) {
+     if (_not_flat) st->print(":not flat");
+     if (_not_null_free) st->print(":nullable");
+   }
    dump_offset(st);
  }
  #endif
  
  const Type* TypeAryKlassPtr::base_element_type(int& dims) const {

*** 6477,28 ***
  
  //=============================================================================
  // Convenience common pre-built types.
  
  //------------------------------make-------------------------------------------
! const TypeFunc *TypeFunc::make( const TypeTuple *domain, const TypeTuple *range ) {
!   return (TypeFunc*)(new TypeFunc(domain,range))->hashcons();
  }
  
  //------------------------------make-------------------------------------------
! const TypeFunc *TypeFunc::make(ciMethod* method) {
    Compile* C = Compile::current();
!   const TypeFunc* tf = C->last_tf(method); // check cache
!   if (tf != nullptr)  return tf;  // The hit rate here is almost 50%.
!   const TypeTuple *domain;
!   if (method->is_static()) {
!     domain = TypeTuple::make_domain(nullptr, method->signature(), ignore_interfaces);
!   } else {
!     domain = TypeTuple::make_domain(method->holder(), method->signature(), ignore_interfaces);
    }
-   const TypeTuple *range  = TypeTuple::make_range(method->signature(), ignore_interfaces);
-   tf = TypeFunc::make(domain, range);
-   C->set_last_tf(method, tf);  // fill cache
    return tf;
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.
--- 7254,54 ---
  
  //=============================================================================
  // Convenience common pre-built types.
  
  //------------------------------make-------------------------------------------
! const TypeFunc *TypeFunc::make(const TypeTuple *domain_sig, const TypeTuple* domain_cc,
!                                const TypeTuple *range_sig, const TypeTuple *range_cc) {
+   return (TypeFunc*)(new TypeFunc(domain_sig, domain_cc, range_sig, range_cc))->hashcons();
+ }
+ 
+ const TypeFunc *TypeFunc::make(const TypeTuple *domain, const TypeTuple *range) {
+   return make(domain, domain, range, range);
+ }
+ 
+ //------------------------------osr_domain-----------------------------
+ const TypeTuple* osr_domain() {
+   const Type **fields = TypeTuple::fields(2);
+   fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM;  // address of osr buffer
+   return TypeTuple::make(TypeFunc::Parms+1, fields);
  }
  
  //------------------------------make-------------------------------------------
! const TypeFunc* TypeFunc::make(ciMethod* method, bool is_osr_compilation) {
    Compile* C = Compile::current();
!   const TypeFunc* tf = nullptr;
!   if (!is_osr_compilation) {
!     tf = C->last_tf(method); // check cache
!     if (tf != nullptr)  return tf;  // The hit rate here is almost 50%.
!   }
!   // Inline types are not passed/returned by reference, instead each field of
!   // the inline type is passed/returned as an argument. We maintain two views of
+   // the argument/return list here: one based on the signature (with an inline
+   // type argument/return as a single slot), one based on the actual calling
+   // convention (with an inline type argument/return as a list of its fields).
+   bool has_scalar_args = method->has_scalarized_args() && !is_osr_compilation;
+   // Fall back to the non-scalarized calling convention when compiling a call via a mismatching method
+   if (method != C->method() && method->get_Method()->mismatch()) {
+     has_scalar_args = false;
+   }
+   const TypeTuple* domain_sig = is_osr_compilation ? osr_domain() : TypeTuple::make_domain(method, ignore_interfaces, false);
+   const TypeTuple* domain_cc = has_scalar_args ? TypeTuple::make_domain(method, ignore_interfaces, true) : domain_sig;
+   ciSignature* sig = method->signature();
+   bool has_scalar_ret = !method->is_native() && sig->return_type()->is_inlinetype() && sig->return_type()->as_inline_klass()->can_be_returned_as_fields();
+   const TypeTuple* range_sig = TypeTuple::make_range(sig, ignore_interfaces, false);
+   const TypeTuple* range_cc = has_scalar_ret ? TypeTuple::make_range(sig, ignore_interfaces, true) : range_sig;
+   tf = TypeFunc::make(domain_sig, domain_cc, range_sig, range_cc);
+   if (!is_osr_compilation) {
+     C->set_last_tf(method, tf);  // fill cache
    }
    return tf;
  }
  
  //------------------------------meet-------------------------------------------
  // Compute the MEET of two types.  It returns a new Type object.

*** 6529,46 ***
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeFunc::eq( const Type *t ) const {
    const TypeFunc *a = (const TypeFunc*)t;
!   return _domain == a->_domain &&
!     _range == a->_range;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeFunc::hash(void) const {
!   return (uint)(uintptr_t)_domain + (uint)(uintptr_t)_range;
  }
  
  //------------------------------dump2------------------------------------------
  // Dump Function Type
  #ifndef PRODUCT
  void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
!   if( _range->cnt() <= Parms )
      st->print("void");
    else {
      uint i;
!     for (i = Parms; i < _range->cnt()-1; i++) {
!       _range->field_at(i)->dump2(d,depth,st);
        st->print("/");
      }
!     _range->field_at(i)->dump2(d,depth,st);
    }
    st->print(" ");
    st->print("( ");
    if( !depth || d[this] ) {     // Check for recursive dump
      st->print("...)");
      return;
    }
    d.Insert((void*)this,(void*)this);    // Stop recursion
!   if (Parms < _domain->cnt())
!     _domain->field_at(Parms)->dump2(d,depth-1,st);
!   for (uint i = Parms+1; i < _domain->cnt(); i++) {
      st->print(", ");
!     _domain->field_at(i)->dump2(d,depth-1,st);
    }
    st->print(" )");
  }
  #endif
  
--- 7332,48 ---
  
  //------------------------------eq---------------------------------------------
  // Structural equality check for Type representations
  bool TypeFunc::eq( const Type *t ) const {
    const TypeFunc *a = (const TypeFunc*)t;
!   return _domain_sig == a->_domain_sig &&
!     _domain_cc == a->_domain_cc &&
+     _range_sig == a->_range_sig &&
+     _range_cc == a->_range_cc;
  }
  
  //------------------------------hash-------------------------------------------
  // Type-specific hashing function.
  uint TypeFunc::hash(void) const {
!   return (uint)(intptr_t)_domain_sig + (uint)(intptr_t)_domain_cc + (uint)(intptr_t)_range_sig + (uint)(intptr_t)_range_cc;
  }
  
  //------------------------------dump2------------------------------------------
  // Dump Function Type
  #ifndef PRODUCT
  void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
!   if( _range_sig->cnt() <= Parms )
      st->print("void");
    else {
      uint i;
!     for (i = Parms; i < _range_sig->cnt()-1; i++) {
!       _range_sig->field_at(i)->dump2(d,depth,st);
        st->print("/");
      }
!     _range_sig->field_at(i)->dump2(d,depth,st);
    }
    st->print(" ");
    st->print("( ");
    if( !depth || d[this] ) {     // Check for recursive dump
      st->print("...)");
      return;
    }
    d.Insert((void*)this,(void*)this);    // Stop recursion
!   if (Parms < _domain_sig->cnt())
!     _domain_sig->field_at(Parms)->dump2(d,depth-1,st);
!   for (uint i = Parms+1; i < _domain_sig->cnt(); i++) {
      st->print(", ");
!     _domain_sig->field_at(i)->dump2(d,depth-1,st);
    }
    st->print(" )");
  }
  #endif
  

*** 6584,10 ***
    return false;                 // Never empty
  }
  
  
  BasicType TypeFunc::return_type() const{
!   if (range()->cnt() == TypeFunc::Parms) {
      return T_VOID;
    }
!   return range()->field_at(TypeFunc::Parms)->basic_type();
  }
--- 7389,10 ---
    return false;                 // Never empty
  }
  
  
  BasicType TypeFunc::return_type() const{
!   if (range_sig()->cnt() == TypeFunc::Parms) {
      return T_VOID;
    }
!   return range_sig()->field_at(TypeFunc::Parms)->basic_type();
  }
< prev index next >