hotspot/src/share/vm/oops/methodData.hpp
changeset 22838 82c7497fbad4
parent 22836 e7e511228518
parent 21095 1a04f7b3946e
child 22849 b8670e920530
--- a/hotspot/src/share/vm/oops/methodData.hpp	Wed Oct 16 10:52:41 2013 +0200
+++ b/hotspot/src/share/vm/oops/methodData.hpp	Tue Nov 05 17:38:04 2013 -0800
@@ -72,6 +72,8 @@
 //
 // Overlay for generic profiling data.
 class DataLayout VALUE_OBJ_CLASS_SPEC {
+  friend class VMStructs;
+
 private:
   // Every data layout begins with a header.  This header
   // contains a tag, which is used to indicate the size/layout
@@ -115,7 +117,10 @@
     ret_data_tag,
     branch_data_tag,
     multi_branch_data_tag,
-    arg_info_data_tag
+    arg_info_data_tag,
+    call_type_data_tag,
+    virtual_call_type_data_tag,
+    parameters_type_data_tag
   };
 
   enum {
@@ -163,7 +168,7 @@
   // occurred, and the MDO shows N occurrences of X, we make the
   // simplifying assumption that all N occurrences can be blamed
   // on that BCI.
-  int trap_state() {
+  int trap_state() const {
     return ((_header._struct._flags >> trap_shift) & trap_mask);
   }
 
@@ -173,11 +178,11 @@
     _header._struct._flags = (new_state << trap_shift) | old_flags;
   }
 
-  u1 flags() {
+  u1 flags() const {
     return _header._struct._flags;
   }
 
-  u2 bci() {
+  u2 bci() const {
     return _header._struct._bci;
   }
 
@@ -196,7 +201,7 @@
   void release_set_cell_at(int index, intptr_t value) {
     OrderAccess::release_store_ptr(&_cells[index], value);
   }
-  intptr_t cell_at(int index) {
+  intptr_t cell_at(int index) const {
     return _cells[index];
   }
 
@@ -204,7 +209,7 @@
     assert(flag_number < flag_limit, "oob");
     _header._struct._flags |= (0x1 << flag_number);
   }
-  bool flag_at(int flag_number) {
+  bool flag_at(int flag_number) const {
     assert(flag_number < flag_limit, "oob");
     return (_header._struct._flags & (0x1 << flag_number)) != 0;
   }
@@ -257,19 +262,24 @@
 class     CounterData;
 class       ReceiverTypeData;
 class         VirtualCallData;
+class           VirtualCallTypeData;
 class       RetData;
+class       CallTypeData;
 class   JumpData;
 class     BranchData;
 class   ArrayData;
 class     MultiBranchData;
 class     ArgInfoData;
-
+class     ParametersTypeData;
 
 // 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 TypeStackSlotEntries;
 private:
 #ifndef PRODUCT
   enum {
@@ -283,6 +293,7 @@
 
 protected:
   DataLayout* data() { return _data; }
+  const DataLayout* data() const { return _data; }
 
   enum {
     cell_size = DataLayout::cell_size
@@ -290,7 +301,7 @@
 
 public:
   // How many cells are in this?
-  virtual int cell_count() {
+  virtual int cell_count() const {
     ShouldNotReachHere();
     return -1;
   }
@@ -310,7 +321,7 @@
     assert(0 <= index && index < cell_count(), "oob");
     data()->release_set_cell_at(index, value);
   }
-  intptr_t intptr_at(int index) {
+  intptr_t intptr_at(int index) const {
     assert(0 <= index && index < cell_count(), "oob");
     return data()->cell_at(index);
   }
@@ -320,7 +331,7 @@
   void release_set_uint_at(int index, uint value) {
     release_set_intptr_at(index, (intptr_t) value);
   }
-  uint uint_at(int index) {
+  uint uint_at(int index) const {
     return (uint)intptr_at(index);
   }
   void set_int_at(int index, int value) {
@@ -329,23 +340,23 @@
   void release_set_int_at(int index, int value) {
     release_set_intptr_at(index, (intptr_t) value);
   }
-  int int_at(int index) {
+  int int_at(int index) const {
     return (int)intptr_at(index);
   }
-  int int_at_unchecked(int index) {
+  int int_at_unchecked(int index) const {
     return (int)data()->cell_at(index);
   }
   void set_oop_at(int index, oop value) {
-    set_intptr_at(index, (intptr_t) value);
+    set_intptr_at(index, cast_from_oop<intptr_t>(value));
   }
-  oop oop_at(int index) {
-    return (oop)intptr_at(index);
+  oop oop_at(int index) const {
+    return cast_to_oop(intptr_at(index));
   }
 
   void set_flag_at(int flag_number) {
     data()->set_flag_at(flag_number);
   }
-  bool flag_at(int flag_number) {
+  bool flag_at(int flag_number) const {
     return data()->flag_at(flag_number);
   }
 
@@ -400,7 +411,7 @@
   // Constructor for invalid ProfileData.
   ProfileData();
 
-  u2 bci() {
+  u2 bci() const {
     return data()->bci();
   }
 
@@ -408,7 +419,7 @@
     return (address)_data;
   }
 
-  int trap_state() {
+  int trap_state() const {
     return data()->trap_state();
   }
   void set_trap_state(int new_state) {
@@ -416,58 +427,73 @@
   }
 
   // Type checking
-  virtual bool is_BitData()         { return false; }
-  virtual bool is_CounterData()     { return false; }
-  virtual bool is_JumpData()        { return false; }
-  virtual bool is_ReceiverTypeData(){ return false; }
-  virtual bool is_VirtualCallData() { return false; }
-  virtual bool is_RetData()         { return false; }
-  virtual bool is_BranchData()      { return false; }
-  virtual bool is_ArrayData()       { return false; }
-  virtual bool is_MultiBranchData() { return false; }
-  virtual bool is_ArgInfoData()     { return false; }
+  virtual bool is_BitData()         const { return false; }
+  virtual bool is_CounterData()     const { return false; }
+  virtual bool is_JumpData()        const { return false; }
+  virtual bool is_ReceiverTypeData()const { return false; }
+  virtual bool is_VirtualCallData() const { return false; }
+  virtual bool is_RetData()         const { return false; }
+  virtual bool is_BranchData()      const { return false; }
+  virtual bool is_ArrayData()       const { return false; }
+  virtual bool is_MultiBranchData() const { return false; }
+  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; }
 
 
-  BitData* as_BitData() {
+  BitData* as_BitData() const {
     assert(is_BitData(), "wrong type");
     return is_BitData()         ? (BitData*)        this : NULL;
   }
-  CounterData* as_CounterData() {
+  CounterData* as_CounterData() const {
     assert(is_CounterData(), "wrong type");
     return is_CounterData()     ? (CounterData*)    this : NULL;
   }
-  JumpData* as_JumpData() {
+  JumpData* as_JumpData() const {
     assert(is_JumpData(), "wrong type");
     return is_JumpData()        ? (JumpData*)       this : NULL;
   }
-  ReceiverTypeData* as_ReceiverTypeData() {
+  ReceiverTypeData* as_ReceiverTypeData() const {
     assert(is_ReceiverTypeData(), "wrong type");
     return is_ReceiverTypeData() ? (ReceiverTypeData*)this : NULL;
   }
-  VirtualCallData* as_VirtualCallData() {
+  VirtualCallData* as_VirtualCallData() const {
     assert(is_VirtualCallData(), "wrong type");
     return is_VirtualCallData() ? (VirtualCallData*)this : NULL;
   }
-  RetData* as_RetData() {
+  RetData* as_RetData() const {
     assert(is_RetData(), "wrong type");
     return is_RetData()         ? (RetData*)        this : NULL;
   }
-  BranchData* as_BranchData() {
+  BranchData* as_BranchData() const {
     assert(is_BranchData(), "wrong type");
     return is_BranchData()      ? (BranchData*)     this : NULL;
   }
-  ArrayData* as_ArrayData() {
+  ArrayData* as_ArrayData() const {
     assert(is_ArrayData(), "wrong type");
     return is_ArrayData()       ? (ArrayData*)      this : NULL;
   }
-  MultiBranchData* as_MultiBranchData() {
+  MultiBranchData* as_MultiBranchData() const {
     assert(is_MultiBranchData(), "wrong type");
     return is_MultiBranchData() ? (MultiBranchData*)this : NULL;
   }
-  ArgInfoData* as_ArgInfoData() {
+  ArgInfoData* as_ArgInfoData() const {
     assert(is_ArgInfoData(), "wrong type");
     return is_ArgInfoData() ? (ArgInfoData*)this : NULL;
   }
+  CallTypeData* as_CallTypeData() const {
+    assert(is_CallTypeData(), "wrong type");
+    return is_CallTypeData() ? (CallTypeData*)this : NULL;
+  }
+  VirtualCallTypeData* as_VirtualCallTypeData() const {
+    assert(is_VirtualCallTypeData(), "wrong type");
+    return is_VirtualCallTypeData() ? (VirtualCallTypeData*)this : NULL;
+  }
+  ParametersTypeData* as_ParametersTypeData() const {
+    assert(is_ParametersTypeData(), "wrong type");
+    return is_ParametersTypeData() ? (ParametersTypeData*)this : NULL;
+  }
 
 
   // Subclass specific initialization
@@ -481,15 +507,15 @@
   // an oop in a ProfileData to the ci equivalent. Generally speaking,
   // most ProfileData don't require any translation, so we provide the null
   // translation here, and the required translators are in the ci subclasses.
-  virtual void translate_from(ProfileData* data) {}
+  virtual void translate_from(const ProfileData* data) {}
 
-  virtual void print_data_on(outputStream* st) {
+  virtual void print_data_on(outputStream* st) const {
     ShouldNotReachHere();
   }
 
 #ifndef PRODUCT
-  void print_shared(outputStream* st, const char* name);
-  void tab(outputStream* st);
+  void print_shared(outputStream* st, const char* name) const;
+  void tab(outputStream* st, bool first = false) const;
 #endif
 };
 
@@ -508,13 +534,13 @@
   BitData(DataLayout* layout) : ProfileData(layout) {
   }
 
-  virtual bool is_BitData() { return true; }
+  virtual bool is_BitData() const { return true; }
 
   static int static_cell_count() {
     return bit_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -550,7 +576,7 @@
 #endif // CC_INTERP
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -566,18 +592,18 @@
 public:
   CounterData(DataLayout* layout) : BitData(layout) {}
 
-  virtual bool is_CounterData() { return true; }
+  virtual bool is_CounterData() const { return true; }
 
   static int static_cell_count() {
     return counter_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
   // Direct accessor
-  uint count() {
+  uint count() const {
     return uint_at(count_off);
   }
 
@@ -613,7 +639,7 @@
 #endif // CC_INTERP
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -641,18 +667,18 @@
       layout->tag() == DataLayout::branch_data_tag, "wrong type");
   }
 
-  virtual bool is_JumpData() { return true; }
+  virtual bool is_JumpData() const { return true; }
 
   static int static_cell_count() {
     return jump_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
   // Direct accessor
-  uint taken() {
+  uint taken() const {
     return uint_at(taken_off_set);
   }
 
@@ -669,7 +695,7 @@
     return cnt;
   }
 
-  int displacement() {
+  int displacement() const {
     return int_at(displacement_off_set);
   }
 
@@ -700,7 +726,417 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+// Entries in a ProfileData object to record types: it can either be
+// none (no profile), unknown (conflicting profile data) or a klass if
+// a single one is seen. Whether a null reference was seen is also
+// recorded. No counter is associated with the type and a single type
+// is tracked (unlike VirtualCallData).
+class TypeEntries {
+
+public:
+
+  // A single cell is used to record information for a type:
+  // - the cell is initialized to 0
+  // - when a type is discovered it is stored in the cell
+  // - bit zero of the cell is used to record whether a null reference
+  // was encountered or not
+  // - bit 1 is set to record a conflict in the type information
+
+  enum {
+    null_seen = 1,
+    type_mask = ~null_seen,
+    type_unknown = 2,
+    status_bits = null_seen | type_unknown,
+    type_klass_mask = ~status_bits
+  };
+
+  // what to initialize a cell to
+  static intptr_t type_none() {
+    return 0;
+  }
+
+  // null seen = bit 0 set?
+  static bool was_null_seen(intptr_t v) {
+    return (v & null_seen) != 0;
+  }
+
+  // conflicting type information = bit 1 set?
+  static bool is_type_unknown(intptr_t v) {
+    return (v & type_unknown) != 0;
+  }
+
+  // not type information yet = all bits cleared, ignoring bit 0?
+  static bool is_type_none(intptr_t v) {
+    return (v & type_mask) == 0;
+  }
+
+  // recorded type: cell without bit 0 and 1
+  static intptr_t klass_part(intptr_t v) {
+    intptr_t r = v & type_klass_mask;
+    assert (r != 0, "invalid");
+    return r;
+  }
+
+  // type recorded
+  static Klass* valid_klass(intptr_t k) {
+    if (!is_type_none(k) &&
+        !is_type_unknown(k)) {
+      return (Klass*)klass_part(k);
+    } else {
+      return NULL;
+    }
+  }
+
+  static intptr_t with_status(intptr_t k, intptr_t in) {
+    return k | (in & status_bits);
+  }
+
+  static intptr_t with_status(Klass* k, intptr_t in) {
+    return with_status((intptr_t)k, in);
+  }
+
+#ifndef PRODUCT
+  static void print_klass(outputStream* st, intptr_t k);
+#endif
+
+  // GC support
+  static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p);
+
+protected:
+  // ProfileData object these entries are part of
+  ProfileData* _pd;
+  // offset within the ProfileData object where the entries start
+  const int _base_off;
+
+  TypeEntries(int base_off)
+    : _base_off(base_off), _pd(NULL) {}
+
+  void set_intptr_at(int index, intptr_t value) {
+    _pd->set_intptr_at(index, value);
+  }
+
+  intptr_t intptr_at(int index) const {
+    return _pd->intptr_at(index);
+  }
+
+public:
+  void set_profile_data(ProfileData* pd) {
+    _pd = pd;
+  }
+};
+
+// Type entries used for arguments passed at a call and parameters on
+// method entry. 2 cells per entry: one for the type encoded as in
+// TypeEntries and one initialized with the stack slot where the
+// profiled object is to be found so that the interpreter can locate
+// it quickly.
+class TypeStackSlotEntries : public TypeEntries {
+
+private:
+  enum {
+    stack_slot_entry,
+    type_entry,
+    per_arg_cell_count
+  };
+
+  // offset of cell for stack slot for entry i within ProfileData object
+  int stack_slot_offset(int i) const {
+    return _base_off + stack_slot_local_offset(i);
+  }
+
+protected:
+  const int _number_of_entries;
+
+  // offset of cell for type for entry i within ProfileData object
+  int type_offset(int i) const {
+    return _base_off + type_local_offset(i);
+  }
+
+public:
+
+  TypeStackSlotEntries(int base_off, int nb_entries)
+    : TypeEntries(base_off), _number_of_entries(nb_entries) {}
+
+  static int compute_cell_count(Symbol* signature, bool include_receiver, int max);
+
+  void post_initialize(Symbol* signature, bool has_receiver, bool include_receiver);
+
+  // offset of cell for stack slot for entry i within this block of cells for a TypeStackSlotEntries
+  static int stack_slot_local_offset(int i) {
+    return i * per_arg_cell_count + stack_slot_entry;
+  }
+
+  // offset of cell for type for entry i within this block of cells for a TypeStackSlotEntries
+  static int type_local_offset(int i) {
+    return i * per_arg_cell_count + type_entry;
+  }
+
+  // stack slot for entry i
+  uint stack_slot(int i) const {
+    assert(i >= 0 && i < _number_of_entries, "oob");
+    return _pd->uint_at(stack_slot_offset(i));
+  }
+
+  // set stack slot for entry i
+  void set_stack_slot(int i, uint num) {
+    assert(i >= 0 && i < _number_of_entries, "oob");
+    _pd->set_uint_at(stack_slot_offset(i), num);
+  }
+
+  // type for entry i
+  intptr_t type(int i) const {
+    assert(i >= 0 && i < _number_of_entries, "oob");
+    return _pd->intptr_at(type_offset(i));
+  }
+
+  // set type for entry i
+  void set_type(int i, intptr_t k) {
+    assert(i >= 0 && i < _number_of_entries, "oob");
+    _pd->set_intptr_at(type_offset(i), k);
+  }
+
+  static ByteSize per_arg_size() {
+    return in_ByteSize(per_arg_cell_count * DataLayout::cell_size);
+  }
+
+  static int per_arg_count() {
+    return per_arg_cell_count ;
+  }
+
+  // GC support
+  void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+// Type entry used for return from a call. A single cell to record the
+// type.
+class ReturnTypeEntry : public TypeEntries {
+
+private:
+  enum {
+    cell_count = 1
+  };
+
+public:
+  ReturnTypeEntry(int base_off)
+    : TypeEntries(base_off) {}
+
+  void post_initialize() {
+    set_type(type_none());
+  }
+
+  intptr_t type() const {
+    return _pd->intptr_at(_base_off);
+  }
+
+  void set_type(intptr_t k) {
+    _pd->set_intptr_at(_base_off, k);
+  }
+
+  static int static_cell_count() {
+    return cell_count;
+  }
+
+  static ByteSize size() {
+    return in_ByteSize(cell_count * DataLayout::cell_size);
+  }
+
+  ByteSize type_offset() {
+    return DataLayout::cell_offset(_base_off);
+  }
+
+  // GC support
+  void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+// Entries to collect type information at a call: contains arguments
+// (TypeStackSlotEntries), a return type (ReturnTypeEntry) 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().
+class TypeEntriesAtCall {
+private:
+  static int stack_slot_local_offset(int i) {
+    return header_cell_count() + TypeStackSlotEntries::stack_slot_local_offset(i);
+  }
+
+  static int argument_type_local_offset(int i) {
+    return header_cell_count() + TypeStackSlotEntries::type_local_offset(i);;
+  }
+
+public:
+
+  static int header_cell_count() {
+    return 1;
+  }
+
+  static int cell_count_local_offset() {
+    return 0;
+  }
+
+  static int compute_cell_count(BytecodeStream* stream);
+
+  static void initialize(DataLayout* dl, int base, int cell_count) {
+    int off = base + cell_count_local_offset();
+    dl->set_cell_at(off, cell_count - base - header_cell_count());
+  }
+
+  static bool arguments_profiling_enabled();
+  static bool return_profiling_enabled();
+
+  // Code generation support
+  static ByteSize cell_count_offset() {
+    return in_ByteSize(cell_count_local_offset() * DataLayout::cell_size);
+  }
+
+  static ByteSize args_data_offset() {
+    return in_ByteSize(header_cell_count() * DataLayout::cell_size);
+  }
+
+  static ByteSize stack_slot_offset(int i) {
+    return in_ByteSize(stack_slot_local_offset(i) * DataLayout::cell_size);
+  }
+
+  static ByteSize argument_type_offset(int i) {
+    return in_ByteSize(argument_type_local_offset(i) * DataLayout::cell_size);
+  }
+};
+
+// CallTypeData
+//
+// A CallTypeData is used to access profiling information about a non
+// virtual call for which we collect type information about arguments
+// and return value.
+class CallTypeData : public CounterData {
+private:
+  // entries for arguments if any
+  TypeStackSlotEntries _args;
+  // entry for return type if any
+  ReturnTypeEntry _ret;
+
+  int cell_count_global_offset() const {
+    return CounterData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
+  }
+
+  // number of cells not counting the header
+  int cell_count_no_header() const {
+    return uint_at(cell_count_global_offset());
+  }
+
+  void check_number_of_arguments(int total) {
+    assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
+  }
+
+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())
+  {
+    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);
+  }
+
+  const TypeStackSlotEntries* args() const {
+    assert(has_arguments(), "no profiling of arguments");
+    return &_args;
+  }
+
+  const ReturnTypeEntry* ret() const {
+    assert(has_return(), "no profiling of return value");
+    return &_ret;
+  }
+
+  virtual bool is_CallTypeData() const { return true; }
+
+  static int static_cell_count() {
+    return -1;
+  }
+
+  static int compute_cell_count(BytecodeStream* stream) {
+    return CounterData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream);
+  }
+
+  static void initialize(DataLayout* dl, int cell_count) {
+    TypeEntriesAtCall::initialize(dl, CounterData::static_cell_count(), cell_count);
+  }
+
+  virtual void post_initialize(BytecodeStream* stream, MethodData* mdo);
+
+  virtual int cell_count() const {
+    return CounterData::static_cell_count() +
+      TypeEntriesAtCall::header_cell_count() +
+      int_at_unchecked(cell_count_global_offset());
+  }
+
+  int number_of_arguments() const {
+    return cell_count_no_header() / TypeStackSlotEntries::per_arg_count();
+  }
+
+  void set_argument_type(int i, Klass* k) {
+    assert(has_arguments(), "no arguments!");
+    intptr_t current = _args.type(i);
+    _args.set_type(i, TypeEntries::with_status(k, current));
+  }
+
+  void set_return_type(Klass* k) {
+    assert(has_return(), "no return!");
+    intptr_t current = _ret.type();
+    _ret.set_type(TypeEntries::with_status(k, current));
+  }
+
+  // An entry for a return value takes less space than an entry for an
+  // argument so if the number of cells exceeds the number of cells
+  // needed for an argument, this object contains type information for
+  // at least one argument.
+  bool has_arguments() const {
+    bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
+    assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
+    return res;
+  }
+
+  // An entry for a return value takes less space than an entry for an
+  // argument, so if the remainder of the number of cells divided by
+  // the number of cells for an argument is not null, a return value
+  // is profiled in this object.
+  bool has_return() const {
+    bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0;
+    assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values");
+    return res;
+  }
+
+  // Code generation support
+  static ByteSize args_data_offset() {
+    return cell_offset(CounterData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
+  }
+
+  // GC support
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
+    if (has_arguments()) {
+      _args.clean_weak_klass_links(is_alive_closure);
+    }
+    if (has_return()) {
+      _ret.clean_weak_klass_links(is_alive_closure);
+    }
+  }
+
+#ifndef PRODUCT
+  virtual void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -721,16 +1157,17 @@
 public:
   ReceiverTypeData(DataLayout* layout) : CounterData(layout) {
     assert(layout->tag() == DataLayout::receiver_type_data_tag ||
-           layout->tag() == DataLayout::virtual_call_data_tag, "wrong type");
+           layout->tag() == DataLayout::virtual_call_data_tag ||
+           layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
   }
 
-  virtual bool is_ReceiverTypeData() { return true; }
+  virtual bool is_ReceiverTypeData() const { return true; }
 
   static int static_cell_count() {
     return counter_cell_count + (uint) TypeProfileWidth * receiver_type_row_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -745,7 +1182,7 @@
     return count0_offset + row * receiver_type_row_cell_count;
   }
 
-  Klass* receiver(uint row) {
+  Klass* receiver(uint row) const {
     assert(row < row_limit(), "oob");
 
     Klass* recv = (Klass*)intptr_at(receiver_cell_index(row));
@@ -758,7 +1195,7 @@
     set_intptr_at(receiver_cell_index(row), (uintptr_t)k);
   }
 
-  uint receiver_count(uint row) {
+  uint receiver_count(uint row) const {
     assert(row < row_limit(), "oob");
     return uint_at(receiver_count_cell_index(row));
   }
@@ -843,8 +1280,8 @@
 #endif // CC_INTERP
 
 #ifndef PRODUCT
-  void print_receiver_data_on(outputStream* st);
-  void print_data_on(outputStream* st);
+  void print_receiver_data_on(outputStream* st) const;
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -855,10 +1292,11 @@
 class VirtualCallData : public ReceiverTypeData {
 public:
   VirtualCallData(DataLayout* layout) : ReceiverTypeData(layout) {
-    assert(layout->tag() == DataLayout::virtual_call_data_tag, "wrong type");
+    assert(layout->tag() == DataLayout::virtual_call_data_tag ||
+           layout->tag() == DataLayout::virtual_call_type_data_tag, "wrong type");
   }
 
-  virtual bool is_VirtualCallData() { return true; }
+  virtual bool is_VirtualCallData() const { return true; }
 
   static int static_cell_count() {
     // At this point we could add more profile state, e.g., for arguments.
@@ -866,7 +1304,7 @@
     return ReceiverTypeData::static_cell_count();
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -886,7 +1324,133 @@
 #endif // CC_INTERP
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+// VirtualCallTypeData
+//
+// A VirtualCallTypeData is used to access profiling information about
+// a virtual call for which we collect type information about
+// arguments and return value.
+class VirtualCallTypeData : public VirtualCallData {
+private:
+  // entries for arguments if any
+  TypeStackSlotEntries _args;
+  // entry for return type if any
+  ReturnTypeEntry _ret;
+
+  int cell_count_global_offset() const {
+    return VirtualCallData::static_cell_count() + TypeEntriesAtCall::cell_count_local_offset();
+  }
+
+  // number of cells not counting the header
+  int cell_count_no_header() const {
+    return uint_at(cell_count_global_offset());
+  }
+
+  void check_number_of_arguments(int total) {
+    assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
+  }
+
+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())
+  {
+    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);
+  }
+
+  const TypeStackSlotEntries* args() const {
+    assert(has_arguments(), "no profiling of arguments");
+    return &_args;
+  }
+
+  const ReturnTypeEntry* ret() const {
+    assert(has_return(), "no profiling of return value");
+    return &_ret;
+  }
+
+  virtual bool is_VirtualCallTypeData() const { return true; }
+
+  static int static_cell_count() {
+    return -1;
+  }
+
+  static int compute_cell_count(BytecodeStream* stream) {
+    return VirtualCallData::static_cell_count() + TypeEntriesAtCall::compute_cell_count(stream);
+  }
+
+  static void initialize(DataLayout* dl, int cell_count) {
+    TypeEntriesAtCall::initialize(dl, VirtualCallData::static_cell_count(), cell_count);
+  }
+
+  virtual void post_initialize(BytecodeStream* stream, MethodData* mdo);
+
+  virtual int cell_count() const {
+    return VirtualCallData::static_cell_count() +
+      TypeEntriesAtCall::header_cell_count() +
+      int_at_unchecked(cell_count_global_offset());
+  }
+
+  int number_of_arguments() const {
+    return cell_count_no_header() / TypeStackSlotEntries::per_arg_count();
+  }
+
+  void set_argument_type(int i, Klass* k) {
+    assert(has_arguments(), "no arguments!");
+    intptr_t current = _args.type(i);
+    _args.set_type(i, TypeEntries::with_status(k, current));
+  }
+
+  void set_return_type(Klass* k) {
+    assert(has_return(), "no return!");
+    intptr_t current = _ret.type();
+    _ret.set_type(TypeEntries::with_status(k, current));
+  }
+
+  // An entry for a return value takes less space than an entry for an
+  // argument, so if the remainder of the number of cells divided by
+  // the number of cells for an argument is not null, a return value
+  // is profiled in this object.
+  bool has_return() const {
+    bool res = (cell_count_no_header() % TypeStackSlotEntries::per_arg_count()) != 0;
+    assert (!res || TypeEntriesAtCall::return_profiling_enabled(), "no profiling of return values");
+    return res;
+  }
+
+  // An entry for a return value takes less space than an entry for an
+  // argument so if the number of cells exceeds the number of cells
+  // needed for an argument, this object contains type information for
+  // at least one argument.
+  bool has_arguments() const {
+    bool res = cell_count_no_header() >= TypeStackSlotEntries::per_arg_count();
+    assert (!res || TypeEntriesAtCall::arguments_profiling_enabled(), "no profiling of arguments");
+    return res;
+  }
+
+  // Code generation support
+  static ByteSize args_data_offset() {
+    return cell_offset(VirtualCallData::static_cell_count()) + TypeEntriesAtCall::args_data_offset();
+  }
+
+  // GC support
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
+    ReceiverTypeData::clean_weak_klass_links(is_alive_closure);
+    if (has_arguments()) {
+      _args.clean_weak_klass_links(is_alive_closure);
+    }
+    if (has_return()) {
+      _ret.clean_weak_klass_links(is_alive_closure);
+    }
+  }
+
+#ifndef PRODUCT
+  virtual void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -929,7 +1493,7 @@
     assert(layout->tag() == DataLayout::ret_data_tag, "wrong type");
   }
 
-  virtual bool is_RetData() { return true; }
+  virtual bool is_RetData() const { return true; }
 
   enum {
     no_bci = -1 // value of bci when bci1/2 are not in use.
@@ -939,7 +1503,7 @@
     return counter_cell_count + (uint) BciProfileWidth * ret_row_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -957,13 +1521,13 @@
   }
 
   // Direct accessors
-  int bci(uint row) {
+  int bci(uint row) const {
     return int_at(bci_cell_index(row));
   }
-  uint bci_count(uint row) {
+  uint bci_count(uint row) const {
     return uint_at(bci_count_cell_index(row));
   }
-  int bci_displacement(uint row) {
+  int bci_displacement(uint row) const {
     return int_at(bci_displacement_cell_index(row));
   }
 
@@ -989,7 +1553,7 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -1014,18 +1578,18 @@
     assert(layout->tag() == DataLayout::branch_data_tag, "wrong type");
   }
 
-  virtual bool is_BranchData() { return true; }
+  virtual bool is_BranchData() const { return true; }
 
   static int static_cell_count() {
     return branch_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
   // Direct accessor
-  uint not_taken() {
+  uint not_taken() const {
     return uint_at(not_taken_off_set);
   }
 
@@ -1067,7 +1631,7 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -1085,15 +1649,15 @@
     array_start_off_set
   };
 
-  uint array_uint_at(int index) {
+  uint array_uint_at(int index) const {
     int aindex = index + array_start_off_set;
     return uint_at(aindex);
   }
-  int array_int_at(int index) {
+  int array_int_at(int index) const {
     int aindex = index + array_start_off_set;
     return int_at(aindex);
   }
-  oop array_oop_at(int index) {
+  oop array_oop_at(int index) const {
     int aindex = index + array_start_off_set;
     return oop_at(aindex);
   }
@@ -1124,17 +1688,17 @@
 public:
   ArrayData(DataLayout* layout) : ProfileData(layout) {}
 
-  virtual bool is_ArrayData() { return true; }
+  virtual bool is_ArrayData() const { return true; }
 
   static int static_cell_count() {
     return -1;
   }
 
-  int array_len() {
+  int array_len() const {
     return int_at_unchecked(array_len_off_set);
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return array_len() + 1;
   }
 
@@ -1181,29 +1745,29 @@
     assert(layout->tag() == DataLayout::multi_branch_data_tag, "wrong type");
   }
 
-  virtual bool is_MultiBranchData() { return true; }
+  virtual bool is_MultiBranchData() const { return true; }
 
   static int compute_cell_count(BytecodeStream* stream);
 
-  int number_of_cases() {
+  int number_of_cases() const {
     int alen = array_len() - 2; // get rid of default case here.
     assert(alen % per_case_cell_count == 0, "must be even");
     return (alen / per_case_cell_count);
   }
 
-  uint default_count() {
+  uint default_count() const {
     return array_uint_at(default_count_off_set);
   }
-  int default_displacement() {
+  int default_displacement() const {
     return array_int_at(default_disaplacement_off_set);
   }
 
-  uint count_at(int index) {
+  uint count_at(int index) const {
     return array_uint_at(case_array_start +
                          index * per_case_cell_count +
                          relative_count_off_set);
   }
-  int displacement_at(int index) {
+  int displacement_at(int index) const {
     return array_int_at(case_array_start +
                         index * per_case_cell_count +
                         relative_displacement_off_set);
@@ -1260,7 +1824,7 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -1271,14 +1835,14 @@
     assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type");
   }
 
-  virtual bool is_ArgInfoData() { return true; }
+  virtual bool is_ArgInfoData() const { return true; }
 
 
-  int number_of_args() {
+  int number_of_args() const {
     return array_len();
   }
 
-  uint arg_modified(int arg) {
+  uint arg_modified(int arg) const {
     return array_uint_at(arg);
   }
 
@@ -1287,10 +1851,79 @@
   }
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
+// ParametersTypeData
+//
+// A ParametersTypeData is used to access profiling information about
+// types of parameters to a method
+class ParametersTypeData : public ArrayData {
+
+private:
+  TypeStackSlotEntries _parameters;
+
+  static int stack_slot_local_offset(int i) {
+    assert_profiling_enabled();
+    return array_start_off_set + TypeStackSlotEntries::stack_slot_local_offset(i);
+  }
+
+  static int type_local_offset(int i) {
+    assert_profiling_enabled();
+    return array_start_off_set + TypeStackSlotEntries::type_local_offset(i);
+  }
+
+  static bool profiling_enabled();
+  static void assert_profiling_enabled() {
+    assert(profiling_enabled(), "method parameters profiling should be on");
+  }
+
+public:
+  ParametersTypeData(DataLayout* layout) : ArrayData(layout), _parameters(1, number_of_parameters()) {
+    assert(layout->tag() == DataLayout::parameters_type_data_tag, "wrong type");
+    // Some compilers (VC++) don't want this passed in member initialization list
+    _parameters.set_profile_data(this);
+  }
+
+  static int compute_cell_count(Method* m);
+
+  virtual bool is_ParametersTypeData() const { return true; }
+
+  virtual void post_initialize(BytecodeStream* stream, MethodData* mdo);
+
+  int number_of_parameters() const {
+    return array_len() / TypeStackSlotEntries::per_arg_count();
+  }
+
+  const TypeStackSlotEntries* parameters() const { return &_parameters; }
+
+  uint stack_slot(int i) const {
+    return _parameters.stack_slot(i);
+  }
+
+  void set_type(int i, Klass* k) {
+    intptr_t current = _parameters.type(i);
+    _parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current));
+  }
+
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
+    _parameters.clean_weak_klass_links(is_alive_closure);
+  }
+
+#ifndef PRODUCT
+  virtual void print_data_on(outputStream* st) const;
+#endif
+
+  static ByteSize stack_slot_offset(int i) {
+    return cell_offset(stack_slot_local_offset(i));
+  }
+
+  static ByteSize type_offset(int i) {
+    return cell_offset(type_local_offset(i));
+  }
+};
+
 // MethodData*
 //
 // A MethodData* holds information which has been collected about
@@ -1405,6 +2038,10 @@
   // Size of _data array in bytes.  (Excludes header and extra_data fields.)
   int _data_size;
 
+  // data index for the area dedicated to parameters. -1 if no
+  // parameter profiling.
+  int _parameters_type_data_di;
+
   // Beginning of the data entries
   intptr_t _data[1];
 
@@ -1460,6 +2097,24 @@
   // return the argument info cell
   ArgInfoData *arg_info();
 
+  enum {
+    no_type_profile = 0,
+    type_profile_jsr292 = 1,
+    type_profile_all = 2
+  };
+
+  static bool profile_jsr292(methodHandle m, int bci);
+  static int profile_arguments_flag();
+  static bool profile_arguments_jsr292_only();
+  static bool profile_all_arguments();
+  static bool profile_arguments_for_invoke(methodHandle m, int bci);
+  static int profile_return_flag();
+  static bool profile_all_return();
+  static bool profile_return_for_invoke(methodHandle m, int bci);
+  static int profile_parameters_flag();
+  static bool profile_parameters_jsr292_only();
+  static bool profile_all_parameters();
+
 public:
   static int header_size() {
     return sizeof(MethodData)/wordSize;
@@ -1665,6 +2320,16 @@
     }
   }
 
+  // Return pointer to area dedicated to parameters in MDO
+  ParametersTypeData* parameters_type_data() const {
+    return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL;
+  }
+
+  int parameters_type_data_di() const {
+    assert(_parameters_type_data_di != -1, "no args type data");
+    return _parameters_type_data_di;
+  }
+
   // Support for code generation
   static ByteSize data_offset() {
     return byte_offset_of(MethodData, _data[0]);
@@ -1677,6 +2342,10 @@
     return byte_offset_of(MethodData, _backedge_counter);
   }
 
+  static ByteSize parameters_type_data_di_offset() {
+    return byte_offset_of(MethodData, _parameters_type_data_di);
+  }
+
   // Deallocation support - no pointer fields to deallocate
   void deallocate_contents(ClassLoaderData* loader_data) {}
 
@@ -1699,6 +2368,12 @@
   // verification
   void verify_on(outputStream* st);
   void verify_data_on(outputStream* st);
+
+  static bool profile_parameters_for_method(methodHandle m);
+  static bool profile_arguments();
+  static bool profile_return();
+  static bool profile_parameters();
+  static bool profile_return_jsr292_only();
 };
 
 #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP