diff a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp
--- a/src/hotspot/share/opto/type.hpp
+++ b/src/hotspot/share/opto/type.hpp
@@ -23,12 +23,14 @@
  */
 
 #ifndef SHARE_OPTO_TYPE_HPP
 #define SHARE_OPTO_TYPE_HPP
 
+#include "ci/ciInlineKlass.hpp"
 #include "opto/adlcVMDeps.hpp"
 #include "runtime/handles.hpp"
+#include "runtime/sharedRuntime.hpp"
 
 // Portions of code courtesy of Clifford Click
 
 // Optimization - Graph Style
 
@@ -134,10 +136,34 @@
   enum OFFSET_SIGNALS {
     OffsetTop = -2000000000,    // undefined offset
     OffsetBot = -2000000001     // any possible offset
   };
 
+  class Offset {
+  private:
+    int _offset;
+
+  public:
+    explicit Offset(int offset) : _offset(offset) {}
+
+    const Offset meet(const Offset other) const;
+    const Offset dual() const;
+    const Offset add(intptr_t offset) const;
+    bool operator==(const Offset& other) const {
+      return _offset == other._offset;
+    }
+    bool operator!=(const Offset& other) const {
+      return _offset != other._offset;
+    }
+    int get() const { return _offset; }
+
+    void dump2(outputStream *st) const;
+
+    static const Offset top;
+    static const Offset bottom;
+  };
+
   // Min and max WIDEN values.
   enum WIDEN {
     WidenMin = 0,
     WidenMax = 3
   };
@@ -324,10 +350,13 @@
   const TypeAryKlassPtr   *is_aryklassptr() const;    // assert if not AryKlassPtr
 
   virtual bool      is_finite() const;           // Has a finite value
   virtual bool      is_nan()    const;           // Is not a number (NaN)
 
+  bool is_inlinetypeptr() const;
+  virtual ciInlineKlass* inline_klass() const;
+
   // Returns this ptr type or the equivalent ptr type for this compressed pointer.
   const TypePtr* make_ptr() const;
 
   // Returns this oopptr type or the equivalent oopptr type for this compressed pointer.
   // Asserts if the underlying type is not an oopptr or narrowoop.
@@ -722,12 +751,12 @@
     assert(i < _cnt, "oob");
     _fields[i] = t;
   }
 
   static const TypeTuple *make( uint cnt, const Type **fields );
-  static const TypeTuple *make_range(ciSignature *sig, InterfaceHandling interface_handling = ignore_interfaces);
-  static const TypeTuple *make_domain(ciInstanceKlass* recv, ciSignature *sig, InterfaceHandling interface_handling);
+  static const TypeTuple *make_range(ciSignature* sig, InterfaceHandling interface_handling = ignore_interfaces, bool ret_vt_fields = false);
+  static const TypeTuple *make_domain(ciMethod* method, InterfaceHandling interface_handling, bool vt_fields_as_args = false);
 
   // Subroutine call type with space allocated for argument types
   // Memory for Control, I_O, Memory, FramePtr, and ReturnAdr is allocated implicitly
   static const Type **fields( uint arg_cnt );
 
@@ -752,26 +781,33 @@
 };
 
 //------------------------------TypeAry----------------------------------------
 // Class of Array Types
 class TypeAry : public Type {
-  TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
-      _elem(elem), _size(size), _stable(stable) {}
+  TypeAry(const Type* elem, const TypeInt* size, bool stable, bool flat, bool not_flat, bool not_null_free) : Type(Array),
+      _elem(elem), _size(size), _stable(stable), _flat(flat), _not_flat(not_flat), _not_null_free(not_null_free) {}
 public:
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;             // Type specific hashing
   virtual bool singleton(void) const;    // TRUE if type is a singleton
   virtual bool empty(void) const;        // TRUE if type is vacuous
 
 private:
   const Type *_elem;            // Element type of array
   const TypeInt *_size;         // Elements in array
   const bool _stable;           // Are elements @Stable?
+
+  // Inline type array properties
+  const bool _flat;             // Array is flat
+  const bool _not_flat;         // Array is never flat
+  const bool _not_null_free;    // Array is never null-free
+
   friend class TypeAryPtr;
 
 public:
-  static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
+  static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false,
+                             bool flat = false, bool not_flat = false, bool not_null_free = false);
 
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
   bool ary_must_be_exact() const;  // true if arrays of such are never generic
   virtual const TypeAry* remove_speculative() const;
@@ -913,11 +949,11 @@
   static const TypeInterfaces* interfaces(ciKlass*& k, bool klass, bool interface, bool array, InterfaceHandling interface_handling);
 
 public:
   enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR };
 protected:
-  TypePtr(TYPES t, PTR ptr, int offset,
+  TypePtr(TYPES t, PTR ptr, Offset offset,
           const TypePtr* speculative = nullptr,
           int inline_depth = InlineDepthBottom) :
     Type(t), _speculative(speculative), _inline_depth(inline_depth), _offset(offset),
     _ptr(ptr) {}
   static const PTR ptr_meet[lastPTR][lastPTR];
@@ -969,51 +1005,55 @@
     SUBTYPE,
     NOT_SUBTYPE,
     LCA
   };
   template<class T> static TypePtr::MeetResult meet_instptr(PTR& ptr, const TypeInterfaces*& interfaces, const T* this_type,
-                                                            const T* other_type, ciKlass*& res_klass, bool& res_xk);
+                                                            const T* other_type, ciKlass*& res_klass, bool& res_xk, bool& res_flat_array);
+ private:
+  template<class T> static bool is_meet_subtype_of(const T* sub_type, const T* super_type);
+ protected:
 
   template<class T> static MeetResult meet_aryptr(PTR& ptr, const Type*& elem, const T* this_ary, const T* other_ary,
-                                                  ciKlass*& res_klass, bool& res_xk);
+                                                  ciKlass*& res_klass, bool& res_xk, bool &res_flat, bool &res_not_flat, bool &res_not_null_free);
 
   template <class T1, class T2> static bool is_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
   template <class T1, class T2> static bool is_same_java_type_as_helper_for_instance(const T1* this_one, const T2* other);
   template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
   template <class T1, class T2> static bool is_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
   template <class T1, class T2> static bool is_same_java_type_as_helper_for_array(const T1* this_one, const T2* other);
   template <class T1, class T2> static bool maybe_java_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_exact, bool other_exact);
   template <class T1, class T2> static bool is_meet_subtype_of_helper_for_instance(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
   template <class T1, class T2> static bool is_meet_subtype_of_helper_for_array(const T1* this_one, const T2* other, bool this_xk, bool other_xk);
 public:
-  const int _offset;            // Offset into oop, with TOP & BOT
+  const Offset _offset;         // Offset into oop, with TOP & BOT
   const PTR _ptr;               // Pointer equivalence class
 
-  int offset() const { return _offset; }
+  int offset() const { return _offset.get(); }
   PTR ptr()    const { return _ptr; }
 
-  static const TypePtr *make(TYPES t, PTR ptr, int offset,
+  static const TypePtr* make(TYPES t, PTR ptr, Offset offset,
                              const TypePtr* speculative = nullptr,
                              int inline_depth = InlineDepthBottom);
 
   // Return a 'ptr' version of this type
   virtual const TypePtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual intptr_t get_con() const;
 
-  int xadd_offset( intptr_t offset ) const;
+  Type::Offset xadd_offset(intptr_t offset) const;
   virtual const TypePtr* add_offset(intptr_t offset) const;
   virtual const TypePtr* with_offset(intptr_t offset) const;
+  virtual int flat_offset() const { return offset(); }
   virtual bool eq(const Type *t) const;
   virtual uint hash() const;             // Type specific hashing
 
   virtual bool singleton(void) const;    // TRUE if type is a singleton
   virtual bool empty(void) const;        // TRUE if type is vacuous
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xmeet_helper( const Type *t ) const;
-  int meet_offset( int offset ) const;
-  int dual_offset( ) const;
+  Offset meet_offset(int offset) const;
+  Offset dual_offset() const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
   // meet, dual and join over pointer equivalence sets
   PTR meet_ptr( const PTR in_ptr ) const { return ptr_meet[in_ptr][ptr()]; }
   PTR dual_ptr()                   const { return ptr_dual[ptr()];      }
@@ -1037,10 +1077,18 @@
   virtual bool would_improve_ptr(ProfilePtrKind maybe_null) const;
   virtual const TypePtr* with_inline_depth(int depth) const;
 
   virtual bool maybe_null() const { return meet_ptr(Null) == ptr(); }
 
+  virtual bool can_be_inline_type() const { return false; }
+  virtual bool flat_in_array()      const { return false; }
+  virtual bool not_flat_in_array()  const { return true; }
+  virtual bool is_flat()            const { return false; }
+  virtual bool is_not_flat()        const { return false; }
+  virtual bool is_null_free()       const { return false; }
+  virtual bool is_not_null_free()   const { return false; }
+
   // Tests for relation to centerline of type lattice:
   static bool above_centerline(PTR ptr) { return (ptr <= AnyNull); }
   static bool below_centerline(PTR ptr) { return (ptr >= NotNull); }
   // Convenience common pre-built types.
   static const TypePtr *NULL_PTR;
@@ -1054,11 +1102,11 @@
 //------------------------------TypeRawPtr-------------------------------------
 // Class of raw pointers, pointers to things other than Oops.  Examples
 // include the stack pointer, top of heap, card-marking area, handles, etc.
 class TypeRawPtr : public TypePtr {
 protected:
-  TypeRawPtr( PTR ptr, address bits ) : TypePtr(RawPtr,ptr,0), _bits(bits){}
+  TypeRawPtr(PTR ptr, address bits) : TypePtr(RawPtr,ptr,Offset(0)), _bits(bits){}
 public:
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;    // Type specific hashing
 
   const address _bits;          // Constant value, if applicable
@@ -1090,11 +1138,11 @@
   friend class TypeAry;
   friend class TypePtr;
   friend class TypeInstPtr;
   friend class TypeAryPtr;
 protected:
- TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset, int instance_id,
+ 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);
 public:
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;             // Type specific hashing
   virtual bool singleton(void) const;    // TRUE if type is a singleton
@@ -1131,11 +1179,11 @@
 
   // Do not allow interface-vs.-noninterface joins to collapse to top.
   virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
 
   virtual ciKlass* exact_klass_helper() const { return nullptr; }
-  virtual ciKlass* klass() const { return _klass;     }
+  virtual ciKlass* klass() const { return _klass; }
 
 public:
 
   bool is_java_subtype_of(const TypeOopPtr* other) const {
     return is_java_subtype_of_helper(other, klass_is_exact(), other->klass_is_exact());
@@ -1178,11 +1226,11 @@
   // If require_constant, produce a null if a singleton is not possible.
   static const TypeOopPtr* make_from_constant(ciObject* o,
                                               bool require_constant = false);
 
   // Make a generic (unclassed) pointer to an oop.
-  static const TypeOopPtr* make(PTR ptr, int offset, int instance_id,
+  static const TypeOopPtr* make(PTR ptr, Offset offset, int instance_id,
                                 const TypePtr* speculative = nullptr,
                                 int inline_depth = InlineDepthBottom);
 
   ciObject* const_oop()    const { return _const_oop; }
   // Exact klass, possibly an interface or an array of interface
@@ -1197,11 +1245,14 @@
   bool is_ptr_to_narrowoop_nv() const { return _is_ptr_to_narrowoop; }
   bool is_ptr_to_narrowklass_nv() const { return _is_ptr_to_narrowklass; }
   bool is_ptr_to_boxed_value()   const { return _is_ptr_to_boxed_value; }
   bool is_known_instance()       const { return _instance_id > 0; }
   int  instance_id()             const { return _instance_id; }
-  bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
+  bool is_known_instance_field() const { return is_known_instance() && _offset.get() >= 0; }
+
+  virtual bool can_be_inline_type() const { return (_klass == nullptr || _klass->can_be_inline_klass(_klass_is_exact)); }
+  virtual bool can_be_inline_array() const { ShouldNotReachHere(); return false; }
 
   virtual intptr_t get_con() const;
 
   virtual const TypeOopPtr* cast_to_ptr_type(PTR ptr) const;
 
@@ -1260,15 +1311,16 @@
 
 //------------------------------TypeInstPtr------------------------------------
 // Class of Java object pointers, pointing either to non-array Java instances
 // or to a Klass* (including array klasses).
 class TypeInstPtr : public TypeOopPtr {
-  TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int off, int instance_id,
-              const TypePtr* speculative, int inline_depth);
+  TypeInstPtr(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, Offset offset,
+              bool flat_in_array, int instance_id, const TypePtr* speculative,
+              int inline_depth);
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;             // Type specific hashing
-
+  bool _flat_in_array; // Type is flat in arrays
   ciKlass* exact_klass_helper() const;
 
 public:
 
   // Instance klass, ignoring any interface
@@ -1283,54 +1335,56 @@
 
   // Make a pointer to a constant oop.
   static const TypeInstPtr *make(ciObject* o) {
     ciKlass* k = o->klass();
     const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
-    return make(TypePtr::Constant, k, interfaces, true, o, 0, InstanceBot);
+    return make(TypePtr::Constant, k, interfaces, true, o, Offset(0));
   }
   // Make a pointer to a constant oop with offset.
-  static const TypeInstPtr *make(ciObject* o, int offset) {
+  static const TypeInstPtr *make(ciObject* o, Offset offset) {
     ciKlass* k = o->klass();
     const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
-    return make(TypePtr::Constant, k, interfaces, true, o, offset, InstanceBot);
+    return make(TypePtr::Constant, k, interfaces, true, o, offset);
   }
 
   // Make a pointer to some value of type klass.
   static const TypeInstPtr *make(PTR ptr, ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, true, false, interface_handling);
-    return make(ptr, klass, interfaces, false, nullptr, 0, InstanceBot);
+    return make(ptr, klass, interfaces, false, nullptr, Offset(0));
   }
 
   // Make a pointer to some non-polymorphic value of exactly type klass.
   static const TypeInstPtr *make_exact(PTR ptr, ciKlass* klass) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
-    return make(ptr, klass, interfaces, true, nullptr, 0, InstanceBot);
+    return make(ptr, klass, interfaces, true, nullptr, Offset(0));
   }
 
   // Make a pointer to some value of type klass with offset.
-  static const TypeInstPtr *make(PTR ptr, ciKlass* klass, int offset) {
+  static const TypeInstPtr *make(PTR ptr, ciKlass* klass, Offset offset) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(klass, true, false, false, ignore_interfaces);
-    return make(ptr, klass, interfaces, false, nullptr, offset, InstanceBot);
+    return make(ptr, klass, interfaces, false, nullptr, offset);
   }
 
-  static const TypeInstPtr *make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, int offset,
+  // Make a pointer to an oop.
+  static const TypeInstPtr* make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, bool xk, ciObject* o, Offset offset,
+                                 bool flat_in_array = false,
                                  int instance_id = InstanceBot,
                                  const TypePtr* speculative = nullptr,
                                  int inline_depth = InlineDepthBottom);
 
-  static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot) {
+  static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset offset, int instance_id = InstanceBot) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
-    return make(ptr, k, interfaces, xk, o, offset, instance_id);
+    return make(ptr, k, interfaces, xk, o, offset, false, instance_id);
   }
 
   /** Create constant type for a constant boxed value */
   const Type* get_const_boxed_value() const;
 
   // If this is a java.lang.Class constant, return the type for it or null.
   // Pass to Type::get_const_type to turn it to a type, which will usually
   // be a TypeInstPtr, but may also be a TypeInt::INT for int.class, etc.
-  ciType* java_mirror_type() const;
+  ciType* java_mirror_type(bool* is_null_free_array = nullptr) const;
 
   virtual const TypeInstPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const TypeInstPtr* cast_to_exactness(bool klass_is_exact) const;
 
@@ -1343,17 +1397,23 @@
   virtual const TypeInstPtr* remove_speculative() const;
   const TypeInstPtr* with_speculative(const TypePtr* speculative) const;
   virtual const TypePtr* with_inline_depth(int depth) const;
   virtual const TypePtr* with_instance_id(int instance_id) const;
 
+  virtual const TypeInstPtr* cast_to_flat_in_array() const;
+  virtual bool flat_in_array() const { return _flat_in_array; }
+  virtual bool not_flat_in_array() const { return !can_be_inline_type() || (_klass->is_inlinetype() && !flat_in_array()); }
+
   // the core of the computation of the meet of 2 types
   virtual const Type *xmeet_helper(const Type *t) const;
   virtual const TypeInstPtr *xmeet_unloaded(const TypeInstPtr *tinst, const TypeInterfaces* interfaces) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
   const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
 
+  virtual bool can_be_inline_array() const;
+
   // Convenience common pre-built types.
   static const TypeInstPtr *NOTNULL;
   static const TypeInstPtr *BOTTOM;
   static const TypeInstPtr *MIRROR;
   static const TypeInstPtr *MARK;
@@ -1374,32 +1434,40 @@
 //------------------------------TypeAryPtr-------------------------------------
 // Class of Java array pointers
 class TypeAryPtr : public TypeOopPtr {
   friend class Type;
   friend class TypePtr;
+  friend class TypeInstPtr;
 
-  TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
-              int offset, int instance_id, bool is_autobox_cache,
-              const TypePtr* speculative, int inline_depth)
-    : TypeOopPtr(AryPtr,ptr,k,_array_interfaces,xk,o,offset, instance_id, speculative, inline_depth),
+  TypeAryPtr(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
+             Offset offset, Offset field_offset, int instance_id, bool is_autobox_cache,
+             const TypePtr* speculative, int inline_depth)
+    : TypeOopPtr(AryPtr, ptr, k, _array_interfaces, xk, o, offset, field_offset, instance_id, speculative, inline_depth),
     _ary(ary),
-    _is_autobox_cache(is_autobox_cache)
+    _is_autobox_cache(is_autobox_cache),
+    _field_offset(field_offset)
  {
     int dummy;
     bool top_or_bottom = (base_element_type(dummy) == Type::TOP || base_element_type(dummy) == Type::BOTTOM);
 
     if (UseCompressedOops && (elem()->make_oopptr() != nullptr && !top_or_bottom) &&
-        _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes() &&
-        _offset != arrayOopDesc::klass_offset_in_bytes()) {
+        _offset.get() != 0 && _offset.get() != arrayOopDesc::length_offset_in_bytes() &&
+        _offset.get() != arrayOopDesc::klass_offset_in_bytes()) {
       _is_ptr_to_narrowoop = true;
     }
 
   }
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;    // Type specific hashing
   const TypeAry *_ary;          // Array we point into
   const bool     _is_autobox_cache;
+  // For flat inline type arrays, each field of the inline type in
+  // the array has its own memory slice so we need to keep track of
+  // which field is accessed
+  const Offset _field_offset;
+  Offset meet_field_offset(const Type::Offset offset) const;
+  Offset dual_field_offset() const;
 
   ciKlass* compute_klass() const;
 
   // A pointer to delay allocation to Type::Initialize_shared()
 
@@ -1423,21 +1491,30 @@
   const TypeAry* ary() const  { return _ary; }
   const Type*    elem() const { return _ary->_elem; }
   const TypeInt* size() const { return _ary->_size; }
   bool      is_stable() const { return _ary->_stable; }
 
+  // Inline type array properties
+  bool is_flat()          const { return _ary->_flat; }
+  bool is_not_flat()      const { return _ary->_not_flat; }
+  bool is_null_free()     const { return is_flat() || (_ary->_elem->make_ptr() != nullptr && _ary->_elem->make_ptr()->is_inlinetypeptr() && (_ary->_elem->make_ptr()->ptr() == NotNull || _ary->_elem->make_ptr()->ptr() == AnyNull)); }
+  bool is_not_null_free() const { return _ary->_not_null_free; }
+
   bool is_autobox_cache() const { return _is_autobox_cache; }
 
-  static const TypeAryPtr *make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,
+  static const TypeAryPtr* make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, Offset offset,
+                                Offset field_offset = Offset::bottom,
                                 int instance_id = InstanceBot,
                                 const TypePtr* speculative = nullptr,
                                 int inline_depth = InlineDepthBottom);
   // Constant pointer to array
-  static const TypeAryPtr *make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset,
+  static const TypeAryPtr* make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset,
+                                Offset field_offset = Offset::bottom,
                                 int instance_id = InstanceBot,
                                 const TypePtr* speculative = nullptr,
-                                int inline_depth = InlineDepthBottom, bool is_autobox_cache = false);
+                                int inline_depth = InlineDepthBottom,
+                                bool is_autobox_cache = false);
 
   // Return a 'ptr' version of this type
   virtual const TypeAryPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const TypeAryPtr* cast_to_exactness(bool klass_is_exact) const;
@@ -1452,25 +1529,43 @@
   virtual const TypeAryPtr *with_offset( intptr_t offset ) const;
   const TypeAryPtr* with_ary(const TypeAry* ary) const;
 
   // Speculative type helper methods.
   virtual const TypeAryPtr* remove_speculative() const;
+  virtual const Type* cleanup_speculative() const;
   virtual const TypePtr* with_inline_depth(int depth) const;
   virtual const TypePtr* with_instance_id(int instance_id) const;
 
   // the core of the computation of the meet of 2 types
   virtual const Type *xmeet_helper(const Type *t) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
+  // Inline type array properties
+  const TypeAryPtr* cast_to_not_flat(bool not_flat = true) const;
+  const TypeAryPtr* cast_to_not_null_free(bool not_null_free = true) const;
+  const TypeAryPtr* update_properties(const TypeAryPtr* new_type) const;
+  jint flat_layout_helper() const;
+  int flat_elem_size() const;
+  int flat_log_elem_size() const;
+
   const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
   int stable_dimension() const;
 
   const TypeAryPtr* cast_to_autobox_cache() const;
 
-  static jint max_array_length(BasicType etype) ;
+  static jint max_array_length(BasicType etype);
+
+  int flat_offset() const;
+  const Offset field_offset() const { return _field_offset; }
+  const TypeAryPtr* with_field_offset(int offset) const;
+  const TypePtr* add_field_offset_and_offset(intptr_t offset) const;
+
+  virtual bool can_be_inline_type() const { return false; }
   virtual const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
 
+  virtual bool can_be_inline_array() const;
+
   // Convenience common pre-built types.
   static const TypeAryPtr *RANGE;
   static const TypeAryPtr *OOPS;
   static const TypeAryPtr *NARROWOOPS;
   static const TypeAryPtr *BYTES;
@@ -1478,10 +1573,11 @@
   static const TypeAryPtr *CHARS;
   static const TypeAryPtr *INTS;
   static const TypeAryPtr *LONGS;
   static const TypeAryPtr *FLOATS;
   static const TypeAryPtr *DOUBLES;
+  static const TypeAryPtr *INLINES;
   // selects one of the above:
   static const TypeAryPtr *get_array_body_type(BasicType elem) {
     assert((uint)elem <= T_CONFLICT && _array_body_type[elem] != nullptr, "bad elem type");
     return _array_body_type[elem];
   }
@@ -1496,11 +1592,11 @@
 
 //------------------------------TypeMetadataPtr-------------------------------------
 // Some kind of metadata, either Method*, MethodData* or CPCacheOop
 class TypeMetadataPtr : public TypePtr {
 protected:
-  TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset);
+  TypeMetadataPtr(PTR ptr, ciMetadata* metadata, Offset offset);
   // Do not allow interface-vs.-noninterface joins to collapse to top.
   virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
 public:
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;             // Type specific hashing
@@ -1508,11 +1604,11 @@
 
 private:
   ciMetadata*   _metadata;
 
 public:
-  static const TypeMetadataPtr* make(PTR ptr, ciMetadata* m, int offset);
+  static const TypeMetadataPtr* make(PTR ptr, ciMetadata* m, Offset offset);
 
   static const TypeMetadataPtr* make(ciMethod* m);
   static const TypeMetadataPtr* make(ciMethodData* m);
 
   ciMetadata* metadata() const { return _metadata; }
@@ -1539,11 +1635,11 @@
 class TypeKlassPtr : public TypePtr {
   friend class TypeInstKlassPtr;
   friend class TypeAryKlassPtr;
   friend class TypePtr;
 protected:
-  TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset);
+  TypeKlassPtr(TYPES t, PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, Offset offset);
 
   virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
 
 public:
   virtual bool eq( const Type *t ) const;
@@ -1578,11 +1674,11 @@
   // Exact klass, possibly an interface or an array of interface
   ciKlass* exact_klass(bool maybe_null = false) const { assert(klass_is_exact(), ""); ciKlass* k = exact_klass_helper(); assert(k != nullptr || maybe_null, ""); return k;  }
   virtual bool klass_is_exact()    const { return _ptr == Constant; }
 
   static const TypeKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling = ignore_interfaces);
-  static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, int offset, InterfaceHandling interface_handling = ignore_interfaces);
+  static const TypeKlassPtr *make(PTR ptr, ciKlass* klass, Offset offset, InterfaceHandling interface_handling = ignore_interfaces);
 
   virtual bool  is_loaded() const { return _klass->is_loaded(); }
 
   virtual const TypeKlassPtr* cast_to_ptr_type(PTR ptr) const { ShouldNotReachHere(); return nullptr; }
 
@@ -1597,10 +1693,11 @@
 
   virtual intptr_t get_con() const;
 
   virtual const TypeKlassPtr* with_offset(intptr_t offset) const { ShouldNotReachHere(); return nullptr; }
 
+  virtual bool can_be_inline_array() const { ShouldNotReachHere(); return false; }
   virtual const TypeKlassPtr* try_improve() const { return this; }
 
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
@@ -1631,17 +1728,19 @@
 };
 
 // Instance klass pointer, mirrors TypeInstPtr
 class TypeInstKlassPtr : public TypeKlassPtr {
 
-  TypeInstKlassPtr(PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, int offset)
-    : TypeKlassPtr(InstKlassPtr, ptr, klass, interfaces, offset) {
+  TypeInstKlassPtr(PTR ptr, ciKlass* klass, const TypeInterfaces* interfaces, Offset offset, bool flat_in_array)
+    : TypeKlassPtr(InstKlassPtr, ptr, klass, interfaces, offset), _flat_in_array(flat_in_array) {
     assert(klass->is_instance_klass() && (!klass->is_loaded() || !klass->is_interface()), "");
   }
 
   virtual bool must_be_exact() const;
 
+  const bool _flat_in_array; // Type is flat in arrays
+
 public:
   // Instance klass ignoring any interface
   ciInstanceKlass* instance_klass() const {
     assert(!klass()->is_interface(), "");
     return klass()->as_instance_klass();
@@ -1649,17 +1748,19 @@
 
   bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
   bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
 
+  virtual bool can_be_inline_type() const { return (_klass == nullptr || _klass->can_be_inline_klass(klass_is_exact())); }
+
   static const TypeInstKlassPtr *make(ciKlass* k, InterfaceHandling interface_handling) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, true, false, interface_handling);
-    return make(TypePtr::Constant, k, interfaces, 0);
+    return make(TypePtr::Constant, k, interfaces, Offset(0));
   }
-  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, int offset);
+  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, const TypeInterfaces* interfaces, Offset offset, bool flat_in_array = false);
 
-  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, int offset) {
+  static const TypeInstKlassPtr* make(PTR ptr, ciKlass* k, Offset offset) {
     const TypeInterfaces* interfaces = TypePtr::interfaces(k, true, false, false, ignore_interfaces);
     return make(ptr, k, interfaces, offset);
   }
 
   virtual const TypeInstKlassPtr* cast_to_ptr_type(PTR ptr) const;
@@ -1676,10 +1777,15 @@
   virtual const Type    *xdual() const;
   virtual const TypeInstKlassPtr* with_offset(intptr_t offset) const;
 
   virtual const TypeKlassPtr* try_improve() const;
 
+  virtual bool flat_in_array() const { return _flat_in_array; }
+  virtual bool not_flat_in_array() const { return !_klass->can_be_inline_klass() || (_klass->is_inlinetype() && !flat_in_array()); }
+
+  virtual bool can_be_inline_array() const;
+
   // Convenience common pre-built types.
   static const TypeInstKlassPtr* OBJECT; // Not-null object klass or below
   static const TypeInstKlassPtr* OBJECT_OR_NULL; // Maybe-null version of same
 private:
   virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
@@ -1690,37 +1796,49 @@
   friend class TypeInstKlassPtr;
   friend class Type;
   friend class TypePtr;
 
   const Type *_elem;
+  const bool _not_flat;      // Array is never flat
+  const bool _not_null_free; // Array is never null-free
+  const bool _null_free;
 
   static const TypeInterfaces* _array_interfaces;
-  TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, int offset)
-    : TypeKlassPtr(AryKlassPtr, ptr, klass, _array_interfaces, offset), _elem(elem) {
-    assert(klass == nullptr || klass->is_type_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "");
+  TypeAryKlassPtr(PTR ptr, const Type *elem, ciKlass* klass, Offset offset, bool not_flat, int not_null_free, bool null_free)
+    : TypeKlassPtr(AryKlassPtr, ptr, klass, _array_interfaces, offset), _elem(elem), _not_flat(not_flat), _not_null_free(not_null_free), _null_free(null_free) {
+    assert(klass == nullptr || klass->is_type_array_klass() || klass->is_flat_array_klass() || !klass->as_obj_array_klass()->base_element_klass()->is_interface(), "");
   }
 
   virtual ciKlass* exact_klass_helper() const;
   // Only guaranteed non null for array of basic types
   virtual ciKlass* klass() const;
 
   virtual bool must_be_exact() const;
 
+  bool dual_null_free() const {
+    return _null_free;
+  }
+
+  bool meet_null_free(bool other) const {
+    return _null_free && other;
+  }
+
 public:
 
   // returns base element type, an instance klass (and not interface) for object arrays
   const Type* base_element_type(int& dims) const;
 
-  static const TypeAryKlassPtr *make(PTR ptr, ciKlass* k, int offset, InterfaceHandling interface_handling);
+  static const TypeAryKlassPtr* make(PTR ptr, ciKlass* k, Offset offset, InterfaceHandling interface_handling, bool not_flat, bool not_null_free, bool null_free);
 
   bool is_same_java_type_as_helper(const TypeKlassPtr* other) const;
   bool is_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
   bool maybe_java_subtype_of_helper(const TypeKlassPtr* other, bool this_exact, bool other_exact) const;
 
   bool  is_loaded() const { return (_elem->isa_klassptr() ? _elem->is_klassptr()->is_loaded() : true); }
 
-  static const TypeAryKlassPtr *make(PTR ptr, const Type *elem, ciKlass* k, int offset);
+  static const TypeAryKlassPtr* make(PTR ptr, const Type* elem, ciKlass* k, Offset offset, bool not_flat, bool not_null_free, bool null_free);
+  static const TypeAryKlassPtr* make(PTR ptr, ciKlass* k, Offset offset, InterfaceHandling interface_handling);
   static const TypeAryKlassPtr* make(ciKlass* klass, InterfaceHandling interface_handling);
 
   const Type *elem() const { return _elem; }
 
   virtual bool eq(const Type *t) const;
@@ -1728,10 +1846,12 @@
 
   virtual const TypeAryKlassPtr* cast_to_ptr_type(PTR ptr) const;
 
   virtual const TypeKlassPtr *cast_to_exactness(bool klass_is_exact) const;
 
+  const TypeAryKlassPtr* cast_to_null_free() const;
+
   // corresponding pointer to instance, for a given class
   virtual const TypeOopPtr* as_instance_type(bool klass_change = true) const;
 
   virtual const TypePtr *add_offset( intptr_t offset ) const;
   virtual const Type    *xmeet( const Type *t ) const;
@@ -1741,10 +1861,16 @@
 
   virtual bool empty(void) const {
     return TypeKlassPtr::empty() || _elem->empty();
   }
 
+  bool is_flat()          const { return klass() != nullptr && klass()->is_flat_array_klass(); }
+  bool is_not_flat()      const { return _not_flat; }
+  bool is_null_free()     const { return _null_free; }
+  bool is_not_null_free() const { return _not_null_free; }
+  virtual bool can_be_inline_array() const;
+
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
 private:
   virtual bool is_meet_subtype_of_helper(const TypeKlassPtr* other, bool this_xk, bool other_xk) const;
@@ -1876,18 +2002,30 @@
 };
 
 //------------------------------TypeFunc---------------------------------------
 // Class of Array Types
 class TypeFunc : public Type {
-  TypeFunc( const TypeTuple *domain, const TypeTuple *range ) : Type(Function),  _domain(domain), _range(range) {}
+  TypeFunc(const TypeTuple *domain_sig, const TypeTuple *domain_cc, const TypeTuple *range_sig, const TypeTuple *range_cc)
+    : Type(Function), _domain_sig(domain_sig), _domain_cc(domain_cc), _range_sig(range_sig), _range_cc(range_cc) {}
   virtual bool eq( const Type *t ) const;
   virtual uint hash() const;             // Type specific hashing
   virtual bool singleton(void) const;    // TRUE if type is a singleton
   virtual bool empty(void) const;        // TRUE if type is vacuous
 
-  const TypeTuple* const _domain;     // Domain of inputs
-  const TypeTuple* const _range;      // Range of results
+  // Domains of inputs: inline type arguments are not passed by
+  // reference, instead each field of the inline type is passed as an
+  // argument. We maintain 2 views of the argument list here: one
+  // based on the signature (with an inline type argument as a single
+  // slot), one based on the actual calling convention (with a value
+  // type argument as a list of its fields).
+  const TypeTuple* const _domain_sig;
+  const TypeTuple* const _domain_cc;
+  // Range of results. Similar to domains: an inline type result can be
+  // returned in registers in which case range_cc lists all fields and
+  // is the actual calling convention.
+  const TypeTuple* const _range_sig;
+  const TypeTuple* const _range_cc;
 
 public:
   // Constants are shared among ADLC and VM
   enum { Control    = AdlcVMDeps::Control,
          I_O        = AdlcVMDeps::I_O,
@@ -1897,22 +2035,27 @@
          Parms      = AdlcVMDeps::Parms
   };
 
 
   // Accessors:
-  const TypeTuple* domain() const { return _domain; }
-  const TypeTuple* range()  const { return _range; }
-
-  static const TypeFunc *make(ciMethod* method);
-  static const TypeFunc *make(ciSignature signature, const Type* extra);
+  const TypeTuple* domain_sig() const { return _domain_sig; }
+  const TypeTuple* domain_cc()  const { return _domain_cc; }
+  const TypeTuple* range_sig()  const { return _range_sig; }
+  const TypeTuple* range_cc()   const { return _range_cc; }
+
+  static const TypeFunc* make(ciMethod* method, bool is_osr_compilation = false);
+  static const TypeFunc *make(const TypeTuple* domain_sig, const TypeTuple* domain_cc,
+                              const TypeTuple* range_sig, const TypeTuple* range_cc);
   static const TypeFunc *make(const TypeTuple* domain, const TypeTuple* range);
 
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
   BasicType return_type() const;
 
+  bool returns_inline_type_as_fields() const { return range_sig() != range_cc(); }
+
 #ifndef PRODUCT
   virtual void dump2( Dict &d, uint depth, outputStream *st ) const; // Specialized per-Type dumping
 #endif
   // Convenience common pre-built types.
 };
@@ -2164,10 +2307,18 @@
       (_base == DoubleCon) || (_base == DoubleBot) )
     return true;
   return false;
 }
 
+inline bool Type::is_inlinetypeptr() const {
+  return isa_instptr() != nullptr && is_instptr()->instance_klass()->is_inlinetype();
+}
+
+inline ciInlineKlass* Type::inline_klass() const {
+  return make_ptr()->is_instptr()->instance_klass()->as_inline_klass();
+}
+
 
 // ===============================================================
 // Things that need to be 64-bits in the 64-bit build but
 // 32-bits in the 32-bit build.  Done this way to get full
 // optimization AND strong typing.
@@ -2190,10 +2341,11 @@
 // For array index arithmetic
 #define MulXNode     MulLNode
 #define AndXNode     AndLNode
 #define OrXNode      OrLNode
 #define CmpXNode     CmpLNode
+#define CmpUXNode    CmpULNode
 #define SubXNode     SubLNode
 #define LShiftXNode  LShiftLNode
 // For object size computation:
 #define AddXNode     AddLNode
 #define RShiftXNode  RShiftLNode
@@ -2208,10 +2360,11 @@
 #define Op_AddX      Op_AddL
 #define Op_SubX      Op_SubL
 #define Op_XorX      Op_XorL
 #define Op_URShiftX  Op_URShiftL
 #define Op_LoadX     Op_LoadL
+#define Op_StoreX    Op_StoreL
 // conversions
 #define ConvI2X(x)   ConvI2L(x)
 #define ConvL2X(x)   (x)
 #define ConvX2I(x)   ConvL2I(x)
 #define ConvX2L(x)   (x)
@@ -2236,10 +2389,11 @@
 // For array index arithmetic
 #define MulXNode     MulINode
 #define AndXNode     AndINode
 #define OrXNode      OrINode
 #define CmpXNode     CmpINode
+#define CmpUXNode    CmpUNode
 #define SubXNode     SubINode
 #define LShiftXNode  LShiftINode
 // For object size computation:
 #define AddXNode     AddINode
 #define RShiftXNode  RShiftINode
@@ -2254,10 +2408,11 @@
 #define Op_AddX      Op_AddI
 #define Op_SubX      Op_SubI
 #define Op_XorX      Op_XorI
 #define Op_URShiftX  Op_URShiftI
 #define Op_LoadX     Op_LoadI
+#define Op_StoreX    Op_StoreI
 // conversions
 #define ConvI2X(x)   (x)
 #define ConvL2X(x)   ConvL2I(x)
 #define ConvX2I(x)   (x)
 #define ConvX2L(x)   ConvI2L(x)
