diff a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp
--- a/src/hotspot/share/oops/methodData.hpp
+++ b/src/hotspot/share/oops/methodData.hpp
@@ -127,11 +127,14 @@
     multi_branch_data_tag,
     arg_info_data_tag,
     call_type_data_tag,
     virtual_call_type_data_tag,
     parameters_type_data_tag,
-    speculative_trap_data_tag
+    speculative_trap_data_tag,
+    array_store_data_tag,
+    array_load_data_tag,
+    acmp_data_tag
   };
 
   enum {
     // The trap state breaks down as [recompile:1 | reason:31].
     // This further breakdown is defined in deoptimization.cpp.
@@ -284,27 +287,30 @@
 class   BitData;
 class     CounterData;
 class       ReceiverTypeData;
 class         VirtualCallData;
 class           VirtualCallTypeData;
+class         ArrayStoreData;
 class       RetData;
 class       CallTypeData;
 class   JumpData;
 class     BranchData;
+class       ACmpData;
 class   ArrayData;
 class     MultiBranchData;
 class     ArgInfoData;
 class     ParametersTypeData;
 class   SpeculativeTrapData;
+class   ArrayLoadData;
 
 // ProfileData
 //
 // A ProfileData object is created to refer to a section of profiling
 // data in a structured way.
 class ProfileData : public ResourceObj {
   friend class TypeEntries;
-  friend class ReturnTypeEntry;
+  friend class SingleTypeEntry;
   friend class TypeStackSlotEntries;
 private:
   enum {
     tab_width_one = 16,
     tab_width_two = 36
@@ -421,10 +427,13 @@
   virtual bool is_ArgInfoData()     const { return false; }
   virtual bool is_CallTypeData()    const { return false; }
   virtual bool is_VirtualCallTypeData()const { return false; }
   virtual bool is_ParametersTypeData() const { return false; }
   virtual bool is_SpeculativeTrapData()const { return false; }
+  virtual bool is_ArrayStoreData() const { return false; }
+  virtual bool is_ArrayLoadData() const { return false; }
+  virtual bool is_ACmpData()           const { return false; }
 
 
   BitData* as_BitData() const {
     assert(is_BitData(), "wrong type");
     return is_BitData()         ? (BitData*)        this : nullptr;
@@ -479,10 +488,22 @@
   }
   SpeculativeTrapData* as_SpeculativeTrapData() const {
     assert(is_SpeculativeTrapData(), "wrong type");
     return is_SpeculativeTrapData() ? (SpeculativeTrapData*)this : nullptr;
   }
+  ArrayStoreData* as_ArrayStoreData() const {
+    assert(is_ArrayStoreData(), "wrong type");
+    return is_ArrayStoreData() ? (ArrayStoreData*)this : nullptr;
+  }
+  ArrayLoadData* as_ArrayLoadData() const {
+    assert(is_ArrayLoadData(), "wrong type");
+    return is_ArrayLoadData() ? (ArrayLoadData*)this : nullptr;
+  }
+  ACmpData* as_ACmpData() const {
+    assert(is_ACmpData(), "wrong type");
+    return is_ACmpData() ? (ACmpData*)this : nullptr;
+  }
 
 
   // Subclass specific initialization
   virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {}
 
@@ -521,10 +542,11 @@
       deprecated_method_callsite_flag = exception_handler_entered_flag + 1
 #if INCLUDE_JVMCI
     // bytecode threw any exception
     , exception_seen_flag             = deprecated_method_callsite_flag + 1
 #endif
+    , last_bit_data_flag
   };
   enum { bit_cell_count = 0 };  // no additional data fields needed.
 public:
   BitData(DataLayout* layout) : ProfileData(layout) {
   }
@@ -541,11 +563,11 @@
 
   // Accessor
 
   // The null_seen flag bit is specially known to the interpreter.
   // Consulting it allows the compiler to avoid setting up null_check traps.
-  bool null_seen()     { return flag_at(null_seen_flag); }
+  bool null_seen() const  { return flag_at(null_seen_flag); }
   void set_null_seen()    { set_flag_at(null_seen_flag); }
   bool deprecated_method_call_site() const { return flag_at(deprecated_method_callsite_flag); }
   bool set_deprecated_method_call_site() { return data()->set_flag_at(deprecated_method_callsite_flag); }
   bool clear_deprecated_method_call_site() { return data()->clear_flag_at(deprecated_method_callsite_flag); }
 
@@ -642,11 +664,12 @@
   }
 
 public:
   JumpData(DataLayout* layout) : ProfileData(layout) {
     assert(layout->tag() == DataLayout::jump_data_tag ||
-      layout->tag() == DataLayout::branch_data_tag, "wrong type");
+      layout->tag() == DataLayout::branch_data_tag ||
+      layout->tag() == DataLayout::acmp_data_tag, "wrong type");
   }
 
   virtual bool is_JumpData() const { return true; }
 
   static int static_cell_count() {
@@ -878,19 +901,19 @@
   void print_data_on(outputStream* st) const;
 };
 
 // Type entry used for return from a call. A single cell to record the
 // type.
-class ReturnTypeEntry : public TypeEntries {
+class SingleTypeEntry : public TypeEntries {
 
 private:
   enum {
     cell_count = 1
   };
 
 public:
-  ReturnTypeEntry(int base_off)
+  SingleTypeEntry(int base_off)
     : TypeEntries(base_off) {}
 
   void post_initialize() {
     set_type(type_none());
   }
@@ -920,11 +943,11 @@
 
   void print_data_on(outputStream* st) const;
 };
 
 // Entries to collect type information at a call: contains arguments
-// (TypeStackSlotEntries), a return type (ReturnTypeEntry) and a
+// (TypeStackSlotEntries), a return type (SingleTypeEntry) and a
 // number of cells. Because the number of cells for the return type is
 // smaller than the number of cells for the type of an arguments, the
 // number of cells is used to tell how many arguments are profiled and
 // whether a return value is profiled. See has_arguments() and
 // has_return().
@@ -974,11 +997,11 @@
   static ByteSize argument_type_offset(int i) {
     return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size);
   }
 
   static ByteSize return_only_size() {
-    return ReturnTypeEntry::size() + in_ByteSize(header_cell_count() * DataLayout::cell_size);
+    return SingleTypeEntry::size() + in_ByteSize(header_cell_count() * DataLayout::cell_size);
   }
 
 };
 
 // CallTypeData
@@ -989,11 +1012,11 @@
 class CallTypeData : public CounterData {
 private:
   // entries for arguments if any
   TypeStackSlotEntries _args;
   // entry for return type if any
-  ReturnTypeEntry _ret;
+  SingleTypeEntry _ret;
 
   int cell_count_global_offset() const {
     return CounterData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
   }
 
@@ -1008,11 +1031,11 @@
 
 public:
   CallTypeData(DataLayout* layout) :
     CounterData(layout),
     _args(CounterData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()),
-    _ret(cell_count() - ReturnTypeEntry::static_cell_count())
+    _ret(cell_count() - SingleTypeEntry::static_cell_count())
   {
     assert(layout->tag() == DataLayout::call_type_data_tag, "wrong type");
     // Some compilers (VC++) don't want this passed in member initialization list
     _args.set_profile_data(this);
     _ret.set_profile_data(this);
@@ -1021,11 +1044,11 @@
   const TypeStackSlotEntries* args() const {
     assert(has_arguments(), "no profiling of arguments");
     return &_args;
   }
 
-  const ReturnTypeEntry* ret() const {
+  const SingleTypeEntry* ret() const {
     assert(has_return(), "no profiling of return value");
     return &_ret;
   }
 
   virtual bool is_CallTypeData() const { return true; }
@@ -1133,11 +1156,12 @@
 
 public:
   ReceiverTypeData(DataLayout* layout) : CounterData(layout) {
     assert(layout->tag() == DataLayout::receiver_type_data_tag ||
            layout->tag() == DataLayout::virtual_call_data_tag ||
-           layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
+           layout->tag() == DataLayout::virtual_call_type_data_tag ||
+           layout->tag() == DataLayout::array_store_data_tag, "wrong type");
   }
 
   virtual bool is_ReceiverTypeData() const { return true; }
 
   static int static_cell_count() {
@@ -1263,11 +1287,11 @@
 class VirtualCallTypeData : public VirtualCallData {
 private:
   // entries for arguments if any
   TypeStackSlotEntries _args;
   // entry for return type if any
-  ReturnTypeEntry _ret;
+  SingleTypeEntry _ret;
 
   int cell_count_global_offset() const {
     return VirtualCallData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
   }
 
@@ -1282,11 +1306,11 @@
 
 public:
   VirtualCallTypeData(DataLayout* layout) :
     VirtualCallData(layout),
     _args(VirtualCallData::static_cell_count()+TypeEntriesAtCall::header_cell_count(), number_of_arguments()),
-    _ret(cell_count() - ReturnTypeEntry::static_cell_count())
+    _ret(cell_count() - SingleTypeEntry::static_cell_count())
   {
     assert(layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
     // Some compilers (VC++) don't want this passed in member initialization list
     _args.set_profile_data(this);
     _ret.set_profile_data(this);
@@ -1295,11 +1319,11 @@
   const TypeStackSlotEntries* args() const {
     assert(has_arguments(), "no profiling of arguments");
     return &_args;
   }
 
-  const ReturnTypeEntry* ret() const {
+  const SingleTypeEntry* ret() const {
     assert(has_return(), "no profiling of return value");
     return &_ret;
   }
 
   virtual bool is_VirtualCallTypeData() const { return true; }
@@ -1497,11 +1521,11 @@
     set_int_at(displacement_off_set, displacement);
   }
 
 public:
   BranchData(DataLayout* layout) : JumpData(layout) {
-    assert(layout->tag() == DataLayout::branch_data_tag, "wrong type");
+    assert(layout->tag() == DataLayout::branch_data_tag || layout->tag() == DataLayout::acmp_data_tag, "wrong type");
   }
 
   virtual bool is_BranchData() const { return true; }
 
   static int static_cell_count() {
@@ -1854,10 +1878,218 @@
   }
 
   virtual void print_data_on(outputStream* st, const char* extra = nullptr) const;
 };
 
+class ArrayStoreData : public ReceiverTypeData {
+private:
+  enum {
+    flat_array_flag = BitData::last_bit_data_flag,
+    null_free_array_flag = flat_array_flag + 1,
+  };
+
+  SingleTypeEntry _array;
+
+public:
+  ArrayStoreData(DataLayout* layout) :
+    ReceiverTypeData(layout),
+    _array(ReceiverTypeData::static_cell_count()) {
+    assert(layout->tag() == DataLayout::array_store_data_tag, "wrong type");
+    _array.set_profile_data(this);
+  }
+
+  const SingleTypeEntry* array() const {
+    return &_array;
+  }
+
+  virtual bool is_ArrayStoreData() const { return true; }
+
+  static int static_cell_count() {
+    return ReceiverTypeData::static_cell_count() + SingleTypeEntry::static_cell_count();
+  }
+
+  virtual int cell_count() const {
+    return static_cell_count();
+  }
+
+  void set_flat_array() { set_flag_at(flat_array_flag); }
+  bool flat_array() const { return flag_at(flat_array_flag); }
+
+  void set_null_free_array() { set_flag_at(null_free_array_flag); }
+  bool null_free_array() const { return flag_at(null_free_array_flag); }
+
+  // Code generation support
+  static int flat_array_byte_constant() {
+    return flag_number_to_constant(flat_array_flag);
+  }
+
+  static int null_free_array_byte_constant() {
+    return flag_number_to_constant(null_free_array_flag);
+  }
+
+  static ByteSize array_offset() {
+    return cell_offset(ReceiverTypeData::static_cell_count());
+  }
+
+  virtual void clean_weak_klass_links(bool always_clean) {
+    ReceiverTypeData::clean_weak_klass_links(always_clean);
+    _array.clean_weak_klass_links(always_clean);
+  }
+
+  static ByteSize array_store_data_size() {
+    return cell_offset(static_cell_count());
+  }
+
+  virtual void print_data_on(outputStream* st, const char* extra = nullptr) const;
+};
+
+class ArrayLoadData : public ProfileData {
+private:
+  enum {
+    flat_array_flag = DataLayout::first_flag,
+    null_free_array_flag = flat_array_flag + 1,
+  };
+
+  SingleTypeEntry _array;
+  SingleTypeEntry _element;
+
+public:
+  ArrayLoadData(DataLayout* layout) :
+    ProfileData(layout),
+    _array(0),
+    _element(SingleTypeEntry::static_cell_count()) {
+    assert(layout->tag() == DataLayout::array_load_data_tag, "wrong type");
+    _array.set_profile_data(this);
+    _element.set_profile_data(this);
+  }
+
+  const SingleTypeEntry* array() const {
+    return &_array;
+  }
+
+  const SingleTypeEntry* element() const {
+    return &_element;
+  }
+
+  virtual bool is_ArrayLoadData() const { return true; }
+
+  static int static_cell_count() {
+    return SingleTypeEntry::static_cell_count() * 2;
+  }
+
+  virtual int cell_count() const {
+    return static_cell_count();
+  }
+
+  void set_flat_array() { set_flag_at(flat_array_flag); }
+  bool flat_array() const { return flag_at(flat_array_flag); }
+
+  void set_null_free_array() { set_flag_at(null_free_array_flag); }
+  bool null_free_array() const { return flag_at(null_free_array_flag); }
+
+  // Code generation support
+  static int flat_array_byte_constant() {
+    return flag_number_to_constant(flat_array_flag);
+  }
+
+  static int null_free_array_byte_constant() {
+    return flag_number_to_constant(null_free_array_flag);
+  }
+
+  static ByteSize array_offset() {
+    return cell_offset(0);
+  }
+
+  static ByteSize element_offset() {
+    return cell_offset(SingleTypeEntry::static_cell_count());
+  }
+
+  virtual void clean_weak_klass_links(bool always_clean) {
+    _array.clean_weak_klass_links(always_clean);
+    _element.clean_weak_klass_links(always_clean);
+  }
+
+  static ByteSize array_load_data_size() {
+    return cell_offset(static_cell_count());
+  }
+
+  virtual void print_data_on(outputStream* st, const char* extra = nullptr) const;
+};
+
+class ACmpData : public BranchData {
+private:
+  enum {
+    left_inline_type_flag = DataLayout::first_flag,
+    right_inline_type_flag
+  };
+
+  SingleTypeEntry _left;
+  SingleTypeEntry _right;
+
+public:
+  ACmpData(DataLayout* layout) :
+    BranchData(layout),
+    _left(BranchData::static_cell_count()),
+    _right(BranchData::static_cell_count() + SingleTypeEntry::static_cell_count()) {
+    assert(layout->tag() == DataLayout::acmp_data_tag, "wrong type");
+    _left.set_profile_data(this);
+    _right.set_profile_data(this);
+  }
+
+  const SingleTypeEntry* left() const {
+    return &_left;
+  }
+
+  const SingleTypeEntry* right() const {
+    return &_right;
+  }
+
+  virtual bool is_ACmpData() const { return true; }
+
+  static int static_cell_count() {
+    return BranchData::static_cell_count() + SingleTypeEntry::static_cell_count() * 2;
+  }
+
+  virtual int cell_count() const {
+    return static_cell_count();
+  }
+
+  void set_left_inline_type() { set_flag_at(left_inline_type_flag); }
+  bool left_inline_type() const { return flag_at(left_inline_type_flag); }
+
+  void set_right_inline_type() { set_flag_at(right_inline_type_flag); }
+  bool right_inline_type() const { return flag_at(right_inline_type_flag); }
+
+  // Code generation support
+  static int left_inline_type_byte_constant() {
+    return flag_number_to_constant(left_inline_type_flag);
+  }
+
+  static int right_inline_type_byte_constant() {
+    return flag_number_to_constant(right_inline_type_flag);
+  }
+
+  static ByteSize left_offset() {
+    return cell_offset(BranchData::static_cell_count());
+  }
+
+  static ByteSize right_offset() {
+    return cell_offset(BranchData::static_cell_count() + SingleTypeEntry::static_cell_count());
+  }
+
+  virtual void clean_weak_klass_links(bool always_clean) {
+    _left.clean_weak_klass_links(always_clean);
+    _right.clean_weak_klass_links(always_clean);
+  }
+
+  static ByteSize acmp_data_size() {
+    return cell_offset(static_cell_count());
+  }
+
+  virtual void print_data_on(outputStream* st, const char* extra = nullptr) const;
+};
+
 // MethodData*
 //
 // A MethodData* holds information which has been collected about
 // a method.  Its layout looks like this:
 //
