hotspot/src/share/vm/oops/methodData.cpp
changeset 22838 82c7497fbad4
parent 22836 e7e511228518
parent 21095 1a04f7b3946e
child 22851 4c4b6a45be43
--- a/hotspot/src/share/vm/oops/methodData.cpp	Wed Oct 16 10:52:41 2013 +0200
+++ b/hotspot/src/share/vm/oops/methodData.cpp	Tue Nov 05 17:38:04 2013 -0800
@@ -41,7 +41,7 @@
 
 // Some types of data layouts need a length field.
 bool DataLayout::needs_array_len(u1 tag) {
-  return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag);
+  return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag) || (tag == parameters_type_data_tag);
 }
 
 // Perform generic initialization of the data.  More specific
@@ -56,6 +56,11 @@
   if (needs_array_len(tag)) {
     set_cell_at(ArrayData::array_len_off_set, cell_count - 1); // -1 for header.
   }
+  if (tag == call_type_data_tag) {
+    CallTypeData::initialize(this, cell_count);
+  } else if (tag == virtual_call_type_data_tag) {
+    VirtualCallTypeData::initialize(this, cell_count);
+  }
 }
 
 void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) {
@@ -76,7 +81,7 @@
 }
 
 #ifndef PRODUCT
-void ProfileData::print_shared(outputStream* st, const char* name) {
+void ProfileData::print_shared(outputStream* st, const char* name) const {
   st->print("bci: %d", bci());
   st->fill_to(tab_width_one);
   st->print("%s", name);
@@ -91,8 +96,8 @@
     st->print("flags(%d) ", flags);
 }
 
-void ProfileData::tab(outputStream* st) {
-  st->fill_to(tab_width_two);
+void ProfileData::tab(outputStream* st, bool first) const {
+  st->fill_to(first ? tab_width_one : tab_width_two);
 }
 #endif // !PRODUCT
 
@@ -104,7 +109,7 @@
 
 
 #ifndef PRODUCT
-void BitData::print_data_on(outputStream* st) {
+void BitData::print_data_on(outputStream* st) const {
   print_shared(st, "BitData");
 }
 #endif // !PRODUCT
@@ -115,7 +120,7 @@
 // A CounterData corresponds to a simple counter.
 
 #ifndef PRODUCT
-void CounterData::print_data_on(outputStream* st) {
+void CounterData::print_data_on(outputStream* st) const {
   print_shared(st, "CounterData");
   st->print_cr("count(%u)", count());
 }
@@ -145,12 +150,217 @@
 }
 
 #ifndef PRODUCT
-void JumpData::print_data_on(outputStream* st) {
+void JumpData::print_data_on(outputStream* st) const {
   print_shared(st, "JumpData");
   st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
 }
 #endif // !PRODUCT
 
+int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) {
+  // Parameter profiling include the receiver
+  int args_count = include_receiver ? 1 : 0;
+  ResourceMark rm;
+  SignatureStream ss(signature);
+  args_count += ss.reference_parameter_count();
+  args_count = MIN2(args_count, max);
+  return args_count * per_arg_cell_count;
+}
+
+int TypeEntriesAtCall::compute_cell_count(BytecodeStream* stream) {
+  assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
+  assert(TypeStackSlotEntries::per_arg_count() > ReturnTypeEntry::static_cell_count(), "code to test for arguments/results broken");
+  Bytecode_invoke inv(stream->method(), stream->bci());
+  int args_cell = 0;
+  if (arguments_profiling_enabled()) {
+    args_cell = TypeStackSlotEntries::compute_cell_count(inv.signature(), false, TypeProfileArgsLimit);
+  }
+  int ret_cell = 0;
+  if (return_profiling_enabled() && (inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY)) {
+    ret_cell = ReturnTypeEntry::static_cell_count();
+  }
+  int header_cell = 0;
+  if (args_cell + ret_cell > 0) {
+    header_cell = header_cell_count();
+  }
+
+  return header_cell + args_cell + ret_cell;
+}
+
+class ArgumentOffsetComputer : public SignatureInfo {
+private:
+  int _max;
+  GrowableArray<int> _offsets;
+
+  void set(int size, BasicType type) { _size += size; }
+  void do_object(int begin, int end) {
+    if (_offsets.length() < _max) {
+      _offsets.push(_size);
+    }
+    SignatureInfo::do_object(begin, end);
+  }
+  void do_array (int begin, int end) {
+    if (_offsets.length() < _max) {
+      _offsets.push(_size);
+    }
+    SignatureInfo::do_array(begin, end);
+  }
+
+public:
+  ArgumentOffsetComputer(Symbol* signature, int max)
+    : SignatureInfo(signature), _max(max), _offsets(Thread::current(), max) {
+  }
+
+  int total() { lazy_iterate_parameters(); return _size; }
+
+  int off_at(int i) const { return _offsets.at(i); }
+};
+
+void TypeStackSlotEntries::post_initialize(Symbol* signature, bool has_receiver, bool include_receiver) {
+  ResourceMark rm;
+  int start = 0;
+  // Parameter profiling include the receiver
+  if (include_receiver && has_receiver) {
+    set_stack_slot(0, 0);
+    set_type(0, type_none());
+    start += 1;
+  }
+  ArgumentOffsetComputer aos(signature, _number_of_entries-start);
+  aos.total();
+  for (int i = start; i < _number_of_entries; i++) {
+    set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0));
+    set_type(i, type_none());
+  }
+}
+
+void CallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
+  assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
+  Bytecode_invoke inv(stream->method(), stream->bci());
+
+  SignatureStream ss(inv.signature());
+  if (has_arguments()) {
+#ifdef ASSERT
+    ResourceMark rm;
+    int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit);
+    assert(count > 0, "room for args type but none found?");
+    check_number_of_arguments(count);
+#endif
+    _args.post_initialize(inv.signature(), inv.has_receiver(), false);
+  }
+
+  if (has_return()) {
+    assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?");
+    _ret.post_initialize();
+  }
+}
+
+void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
+  assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
+  Bytecode_invoke inv(stream->method(), stream->bci());
+
+  if (has_arguments()) {
+#ifdef ASSERT
+    ResourceMark rm;
+    SignatureStream ss(inv.signature());
+    int count = MIN2(ss.reference_parameter_count(), (int)TypeProfileArgsLimit);
+    assert(count > 0, "room for args type but none found?");
+    check_number_of_arguments(count);
+#endif
+    _args.post_initialize(inv.signature(), inv.has_receiver(), false);
+  }
+
+  if (has_return()) {
+    assert(inv.result_type() == T_OBJECT || inv.result_type() == T_ARRAY, "room for a ret type but doesn't return obj?");
+    _ret.post_initialize();
+  }
+}
+
+bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) {
+  return !is_type_none(p) &&
+    !((Klass*)klass_part(p))->is_loader_alive(is_alive_cl);
+}
+
+void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
+  for (int i = 0; i < _number_of_entries; i++) {
+    intptr_t p = type(i);
+    if (is_loader_alive(is_alive_cl, p)) {
+      set_type(i, type_none());
+    }
+  }
+}
+
+void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
+  intptr_t p = type();
+  if (is_loader_alive(is_alive_cl, p)) {
+    set_type(type_none());
+  }
+}
+
+bool TypeEntriesAtCall::return_profiling_enabled() {
+  return MethodData::profile_return();
+}
+
+bool TypeEntriesAtCall::arguments_profiling_enabled() {
+  return MethodData::profile_arguments();
+}
+
+#ifndef PRODUCT
+void TypeEntries::print_klass(outputStream* st, intptr_t k) {
+  if (is_type_none(k)) {
+    st->print("none");
+  } else if (is_type_unknown(k)) {
+    st->print("unknown");
+  } else {
+    valid_klass(k)->print_value_on(st);
+  }
+  if (was_null_seen(k)) {
+    st->print(" (null seen)");
+  }
+}
+
+void TypeStackSlotEntries::print_data_on(outputStream* st) const {
+  for (int i = 0; i < _number_of_entries; i++) {
+    _pd->tab(st);
+    st->print("%d: stack(%u) ", i, stack_slot(i));
+    print_klass(st, type(i));
+    st->cr();
+  }
+}
+
+void ReturnTypeEntry::print_data_on(outputStream* st) const {
+  _pd->tab(st);
+  print_klass(st, type());
+  st->cr();
+}
+
+void CallTypeData::print_data_on(outputStream* st) const {
+  CounterData::print_data_on(st);
+  if (has_arguments()) {
+    tab(st, true);
+    st->print("argument types");
+    _args.print_data_on(st);
+  }
+  if (has_return()) {
+    tab(st, true);
+    st->print("return type");
+    _ret.print_data_on(st);
+  }
+}
+
+void VirtualCallTypeData::print_data_on(outputStream* st) const {
+  VirtualCallData::print_data_on(st);
+  if (has_arguments()) {
+    tab(st, true);
+    st->print("argument types");
+    _args.print_data_on(st);
+  }
+  if (has_return()) {
+    tab(st, true);
+    st->print("return type");
+    _ret.print_data_on(st);
+  }
+}
+#endif
+
 // ==================================================================
 // ReceiverTypeData
 //
@@ -169,7 +379,7 @@
 }
 
 #ifndef PRODUCT
-void ReceiverTypeData::print_receiver_data_on(outputStream* st) {
+void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
   uint row;
   int entries = 0;
   for (row = 0; row < row_limit(); row++) {
@@ -190,11 +400,11 @@
     }
   }
 }
-void ReceiverTypeData::print_data_on(outputStream* st) {
+void ReceiverTypeData::print_data_on(outputStream* st) const {
   print_shared(st, "ReceiverTypeData");
   print_receiver_data_on(st);
 }
-void VirtualCallData::print_data_on(outputStream* st) {
+void VirtualCallData::print_data_on(outputStream* st) const {
   print_shared(st, "VirtualCallData");
   print_receiver_data_on(st);
 }
@@ -251,7 +461,7 @@
 #endif // CC_INTERP
 
 #ifndef PRODUCT
-void RetData::print_data_on(outputStream* st) {
+void RetData::print_data_on(outputStream* st) const {
   print_shared(st, "RetData");
   uint row;
   int entries = 0;
@@ -286,7 +496,7 @@
 }
 
 #ifndef PRODUCT
-void BranchData::print_data_on(outputStream* st) {
+void BranchData::print_data_on(outputStream* st) const {
   print_shared(st, "BranchData");
   st->print_cr("taken(%u) displacement(%d)",
                taken(), displacement());
@@ -360,7 +570,7 @@
 }
 
 #ifndef PRODUCT
-void MultiBranchData::print_data_on(outputStream* st) {
+void MultiBranchData::print_data_on(outputStream* st) const {
   print_shared(st, "MultiBranchData");
   st->print_cr("default_count(%u) displacement(%d)",
                default_count(), default_displacement());
@@ -374,7 +584,7 @@
 #endif
 
 #ifndef PRODUCT
-void ArgInfoData::print_data_on(outputStream* st) {
+void ArgInfoData::print_data_on(outputStream* st) const {
   print_shared(st, "ArgInfoData");
   int nargs = number_of_args();
   for (int i = 0; i < nargs; i++) {
@@ -384,6 +594,34 @@
 }
 
 #endif
+
+int ParametersTypeData::compute_cell_count(Method* m) {
+  if (!MethodData::profile_parameters_for_method(m)) {
+    return 0;
+  }
+  int max = TypeProfileParmsLimit == -1 ? INT_MAX : TypeProfileParmsLimit;
+  int obj_args = TypeStackSlotEntries::compute_cell_count(m->signature(), !m->is_static(), max);
+  if (obj_args > 0) {
+    return obj_args + 1; // 1 cell for array len
+  }
+  return 0;
+}
+
+void ParametersTypeData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
+  _parameters.post_initialize(mdo->method()->signature(), !mdo->method()->is_static(), true);
+}
+
+bool ParametersTypeData::profiling_enabled() {
+  return MethodData::profile_parameters();
+}
+
+#ifndef PRODUCT
+void ParametersTypeData::print_data_on(outputStream* st) const {
+  st->print("parameter types");
+  _parameters.print_data_on(st);
+}
+#endif
+
 // ==================================================================
 // MethodData*
 //
@@ -412,7 +650,11 @@
     }
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokestatic:
-    return CounterData::static_cell_count();
+    if (MethodData::profile_arguments() || MethodData::profile_return()) {
+      return variable_cell_count;
+    } else {
+      return CounterData::static_cell_count();
+    }
   case Bytecodes::_goto:
   case Bytecodes::_goto_w:
   case Bytecodes::_jsr:
@@ -420,9 +662,17 @@
     return JumpData::static_cell_count();
   case Bytecodes::_invokevirtual:
   case Bytecodes::_invokeinterface:
-    return VirtualCallData::static_cell_count();
+    if (MethodData::profile_arguments() || MethodData::profile_return()) {
+      return variable_cell_count;
+    } else {
+      return VirtualCallData::static_cell_count();
+    }
   case Bytecodes::_invokedynamic:
-    return CounterData::static_cell_count();
+    if (MethodData::profile_arguments() || MethodData::profile_return()) {
+      return variable_cell_count;
+    } else {
+      return CounterData::static_cell_count();
+    }
   case Bytecodes::_ret:
     return RetData::static_cell_count();
   case Bytecodes::_ifeq:
@@ -458,7 +708,36 @@
     return 0;
   }
   if (cell_count == variable_cell_count) {
-    cell_count = MultiBranchData::compute_cell_count(stream);
+    switch (stream->code()) {
+    case Bytecodes::_lookupswitch:
+    case Bytecodes::_tableswitch:
+      cell_count = MultiBranchData::compute_cell_count(stream);
+      break;
+    case Bytecodes::_invokespecial:
+    case Bytecodes::_invokestatic:
+    case Bytecodes::_invokedynamic:
+      assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile");
+      if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
+          profile_return_for_invoke(stream->method(), stream->bci())) {
+        cell_count = CallTypeData::compute_cell_count(stream);
+      } else {
+        cell_count = CounterData::static_cell_count();
+      }
+      break;
+    case Bytecodes::_invokevirtual:
+    case Bytecodes::_invokeinterface: {
+      assert(MethodData::profile_arguments() || MethodData::profile_return(), "should be collecting args profile");
+      if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
+          profile_return_for_invoke(stream->method(), stream->bci())) {
+        cell_count = VirtualCallTypeData::compute_cell_count(stream);
+      } else {
+        cell_count = VirtualCallData::static_cell_count();
+      }
+      break;
+    }
+    default:
+      fatal("unexpected bytecode for var length profile data");
+    }
   }
   // Note:  cell_count might be zero, meaning that there is just
   //        a DataLayout header, with no extra cells.
@@ -504,6 +783,13 @@
   // Add a cell to record information about modified arguments.
   int arg_size = method->size_of_parameters();
   object_size += DataLayout::compute_size_in_bytes(arg_size+1);
+
+  // Reserve room for an area of the MDO dedicated to profiling of
+  // parameters
+  int args_cell = ParametersTypeData::compute_cell_count(method());
+  if (args_cell > 0) {
+    object_size += DataLayout::compute_size_in_bytes(args_cell);
+  }
   return object_size;
 }
 
@@ -539,10 +825,21 @@
     }
     break;
   case Bytecodes::_invokespecial:
-  case Bytecodes::_invokestatic:
-    cell_count = CounterData::static_cell_count();
-    tag = DataLayout::counter_data_tag;
+  case Bytecodes::_invokestatic: {
+    int counter_data_cell_count = CounterData::static_cell_count();
+    if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
+        profile_return_for_invoke(stream->method(), stream->bci())) {
+      cell_count = CallTypeData::compute_cell_count(stream);
+    } else {
+      cell_count = counter_data_cell_count;
+    }
+    if (cell_count > counter_data_cell_count) {
+      tag = DataLayout::call_type_data_tag;
+    } else {
+      tag = DataLayout::counter_data_tag;
+    }
     break;
+  }
   case Bytecodes::_goto:
   case Bytecodes::_goto_w:
   case Bytecodes::_jsr:
@@ -551,15 +848,37 @@
     tag = DataLayout::jump_data_tag;
     break;
   case Bytecodes::_invokevirtual:
-  case Bytecodes::_invokeinterface:
-    cell_count = VirtualCallData::static_cell_count();
-    tag = DataLayout::virtual_call_data_tag;
+  case Bytecodes::_invokeinterface: {
+    int virtual_call_data_cell_count = VirtualCallData::static_cell_count();
+    if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
+        profile_return_for_invoke(stream->method(), stream->bci())) {
+      cell_count = VirtualCallTypeData::compute_cell_count(stream);
+    } else {
+      cell_count = virtual_call_data_cell_count;
+    }
+    if (cell_count > virtual_call_data_cell_count) {
+      tag = DataLayout::virtual_call_type_data_tag;
+    } else {
+      tag = DataLayout::virtual_call_data_tag;
+    }
     break;
-  case Bytecodes::_invokedynamic:
+  }
+  case Bytecodes::_invokedynamic: {
     // %%% should make a type profile for any invokedynamic that takes a ref argument
-    cell_count = CounterData::static_cell_count();
-    tag = DataLayout::counter_data_tag;
+    int counter_data_cell_count = CounterData::static_cell_count();
+    if (profile_arguments_for_invoke(stream->method(), stream->bci()) ||
+        profile_return_for_invoke(stream->method(), stream->bci())) {
+      cell_count = CallTypeData::compute_cell_count(stream);
+    } else {
+      cell_count = counter_data_cell_count;
+    }
+    if (cell_count > counter_data_cell_count) {
+      tag = DataLayout::call_type_data_tag;
+    } else {
+      tag = DataLayout::counter_data_tag;
+    }
     break;
+  }
   case Bytecodes::_ret:
     cell_count = RetData::static_cell_count();
     tag = DataLayout::ret_data_tag;
@@ -590,6 +909,11 @@
     break;
   }
   assert(tag == DataLayout::multi_branch_data_tag ||
+         ((MethodData::profile_arguments() || MethodData::profile_return()) &&
+          (tag == DataLayout::call_type_data_tag ||
+           tag == DataLayout::counter_data_tag ||
+           tag == DataLayout::virtual_call_type_data_tag ||
+           tag == DataLayout::virtual_call_data_tag)) ||
          cell_count == bytecode_cell_count(c), "cell counts must agree");
   if (cell_count >= 0) {
     assert(tag != DataLayout::no_tag, "bad tag");
@@ -636,6 +960,12 @@
     return new MultiBranchData(this);
   case DataLayout::arg_info_data_tag:
     return new ArgInfoData(this);
+  case DataLayout::call_type_data_tag:
+    return new CallTypeData(this);
+  case DataLayout::virtual_call_type_data_tag:
+    return new VirtualCallTypeData(this);
+  case DataLayout::parameters_type_data_tag:
+    return new ParametersTypeData(this);
   };
 }
 
@@ -657,6 +987,9 @@
     stream->next();
     data->post_initialize(stream, this);
   }
+  if (_parameters_type_data_di != -1) {
+    parameters_type_data()->post_initialize(NULL, this);
+  }
 }
 
 // Initialize the MethodData* corresponding to a given method.
@@ -696,7 +1029,23 @@
   int arg_size = method->size_of_parameters();
   dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1);
 
-  object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1);
+  int arg_data_size = DataLayout::compute_size_in_bytes(arg_size+1);
+  object_size += extra_size + arg_data_size;
+
+  int args_cell = ParametersTypeData::compute_cell_count(method());
+  // If we are profiling parameters, we reserver an area near the end
+  // of the MDO after the slots for bytecodes (because there's no bci
+  // for method entry so they don't fit with the framework for the
+  // profiling of bytecodes). We store the offset within the MDO of
+  // this area (or -1 if no parameter is profiled)
+  if (args_cell > 0) {
+    object_size += DataLayout::compute_size_in_bytes(args_cell);
+    _parameters_type_data_di = data_size + extra_size + arg_data_size;
+    DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
+    dp->initialize(DataLayout::parameters_type_data_tag, 0, args_cell);
+  } else {
+    _parameters_type_data_di = -1;
+  }
 
   // Set an initial hint. Don't use set_hint_di() because
   // first_di() may be out of bounds if data_size is 0.
@@ -855,6 +1204,9 @@
 void MethodData::print_data_on(outputStream* st) const {
   ResourceMark rm;
   ProfileData* data = first_data();
+  if (_parameters_type_data_di != -1) {
+    parameters_type_data()->print_data_on(st);
+  }
   for ( ; is_valid(data); data = next_data(data)) {
     st->print("%d", dp_to_di(data->dp()));
     st->fill_to(6);
@@ -903,3 +1255,99 @@
   NEEDS_CLEANUP;
   // not yet implemented.
 }
+
+bool MethodData::profile_jsr292(methodHandle m, int bci) {
+  if (m->is_compiled_lambda_form()) {
+    return true;
+  }
+
+  Bytecode_invoke inv(m , bci);
+  return inv.is_invokedynamic() || inv.is_invokehandle();
+}
+
+int MethodData::profile_arguments_flag() {
+  return TypeProfileLevel % 10;
+}
+
+bool MethodData::profile_arguments() {
+  return profile_arguments_flag() > no_type_profile && profile_arguments_flag() <= type_profile_all;
+}
+
+bool MethodData::profile_arguments_jsr292_only() {
+  return profile_arguments_flag() == type_profile_jsr292;
+}
+
+bool MethodData::profile_all_arguments() {
+  return profile_arguments_flag() == type_profile_all;
+}
+
+bool MethodData::profile_arguments_for_invoke(methodHandle m, int bci) {
+  if (!profile_arguments()) {
+    return false;
+  }
+
+  if (profile_all_arguments()) {
+    return true;
+  }
+
+  assert(profile_arguments_jsr292_only(), "inconsistent");
+  return profile_jsr292(m, bci);
+}
+
+int MethodData::profile_return_flag() {
+  return (TypeProfileLevel % 100) / 10;
+}
+
+bool MethodData::profile_return() {
+  return profile_return_flag() > no_type_profile && profile_return_flag() <= type_profile_all;
+}
+
+bool MethodData::profile_return_jsr292_only() {
+  return profile_return_flag() == type_profile_jsr292;
+}
+
+bool MethodData::profile_all_return() {
+  return profile_return_flag() == type_profile_all;
+}
+
+bool MethodData::profile_return_for_invoke(methodHandle m, int bci) {
+  if (!profile_return()) {
+    return false;
+  }
+
+  if (profile_all_return()) {
+    return true;
+  }
+
+  assert(profile_return_jsr292_only(), "inconsistent");
+  return profile_jsr292(m, bci);
+}
+
+int MethodData::profile_parameters_flag() {
+  return TypeProfileLevel / 100;
+}
+
+bool MethodData::profile_parameters() {
+  return profile_parameters_flag() > no_type_profile && profile_parameters_flag() <= type_profile_all;
+}
+
+bool MethodData::profile_parameters_jsr292_only() {
+  return profile_parameters_flag() == type_profile_jsr292;
+}
+
+bool MethodData::profile_all_parameters() {
+  return profile_parameters_flag() == type_profile_all;
+}
+
+bool MethodData::profile_parameters_for_method(methodHandle m) {
+  if (!profile_parameters()) {
+    return false;
+  }
+
+  if (profile_all_parameters()) {
+    return true;
+  }
+
+  assert(profile_parameters_jsr292_only(), "inconsistent");
+  return m->is_compiled_lambda_form();
+}