8023657: New type profiling points: arguments to call
authorroland
Wed, 09 Oct 2013 16:32:21 +0200
changeset 20702 bbe0fcde6e13
parent 20701 ef9996662fd5
child 20703 2de7fe0e9693
child 20705 623e32a8ca34
8023657: New type profiling points: arguments to call Summary: x86 interpreter and c1 type profiling for arguments at calls Reviewed-by: kvn, twisti
hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp
hotspot/src/cpu/sparc/vm/globals_sparc.hpp
hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
hotspot/src/cpu/x86/vm/globals_x86.hpp
hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp
hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp
hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp
hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp
hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp
hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp
hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp
hotspot/src/share/vm/c1/c1_Compilation.cpp
hotspot/src/share/vm/c1/c1_Compilation.hpp
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
hotspot/src/share/vm/c1/c1_GraphBuilder.hpp
hotspot/src/share/vm/c1/c1_Instruction.cpp
hotspot/src/share/vm/c1/c1_Instruction.hpp
hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp
hotspot/src/share/vm/c1/c1_LIR.cpp
hotspot/src/share/vm/c1/c1_LIR.hpp
hotspot/src/share/vm/c1/c1_LIRAssembler.hpp
hotspot/src/share/vm/c1/c1_LIRGenerator.cpp
hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
hotspot/src/share/vm/c1/c1_Optimizer.cpp
hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp
hotspot/src/share/vm/ci/ciClassList.hpp
hotspot/src/share/vm/ci/ciInstanceKlass.hpp
hotspot/src/share/vm/ci/ciKlass.hpp
hotspot/src/share/vm/ci/ciMethodData.cpp
hotspot/src/share/vm/ci/ciMethodData.hpp
hotspot/src/share/vm/ci/ciObjArrayKlass.cpp
hotspot/src/share/vm/ci/ciObjArrayKlass.hpp
hotspot/src/share/vm/ci/ciStreams.hpp
hotspot/src/share/vm/ci/ciTypeArrayKlass.hpp
hotspot/src/share/vm/oops/methodData.cpp
hotspot/src/share/vm/oops/methodData.hpp
hotspot/src/share/vm/runtime/globals.hpp
hotspot/src/share/vm/runtime/java.cpp
hotspot/src/share/vm/runtime/signature.cpp
hotspot/src/share/vm/runtime/signature.hpp
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -3100,6 +3100,10 @@
   }
 }
 
+void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
+  fatal("Type profiling not implemented on this platform");
+}
+
 void LIR_Assembler::align_backward_branch_target() {
   __ align(OptoLoopAlignment);
 }
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -76,6 +76,8 @@
 // GC Ergo Flags
 define_pd_global(uintx, CMSYoungGenPerWorker, 16*M);  // default max size of CMS young gen, per GC worker thread
 
+define_pd_global(uintx, TypeProfileLevel, 0);
+
 #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
                                                                             \
   product(intx, UseVIS, 99,                                                 \
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -3632,6 +3632,161 @@
   }
 }
 
+void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) {
+  Register obj = op->obj()->as_register();
+  Register tmp = op->tmp()->as_pointer_register();
+  Address mdo_addr = as_Address(op->mdp()->as_address_ptr());
+  ciKlass* exact_klass = op->exact_klass();
+  intptr_t current_klass = op->current_klass();
+  bool not_null = op->not_null();
+  bool no_conflict = op->no_conflict();
+
+  Label update, next, none;
+
+  bool do_null = !not_null;
+  bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass;
+  bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set;
+
+  assert(do_null || do_update, "why are we here?");
+  assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?");
+
+  __ verify_oop(obj);
+
+  if (tmp != obj) {
+    __ mov(tmp, obj);
+  }
+  if (do_null) {
+    __ testptr(tmp, tmp);
+    __ jccb(Assembler::notZero, update);
+    if (!TypeEntries::was_null_seen(current_klass)) {
+      __ orptr(mdo_addr, TypeEntries::null_seen);
+    }
+    if (do_update) {
+#ifndef ASSERT
+      __ jmpb(next);
+    }
+#else
+      __ jmp(next);
+    }
+  } else {
+    __ testptr(tmp, tmp);
+    __ jccb(Assembler::notZero, update);
+    __ stop("unexpect null obj");
+#endif
+  }
+
+  __ bind(update);
+
+  if (do_update) {
+#ifdef ASSERT
+    if (exact_klass != NULL) {
+      Label ok;
+      __ load_klass(tmp, tmp);
+      __ push(tmp);
+      __ mov_metadata(tmp, exact_klass->constant_encoding());
+      __ cmpptr(tmp, Address(rsp, 0));
+      __ jccb(Assembler::equal, ok);
+      __ stop("exact klass and actual klass differ");
+      __ bind(ok);
+      __ pop(tmp);
+    }
+#endif
+    if (!no_conflict) {
+      if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) {
+        if (exact_klass != NULL) {
+          __ mov_metadata(tmp, exact_klass->constant_encoding());
+        } else {
+          __ load_klass(tmp, tmp);
+        }
+
+        __ xorptr(tmp, mdo_addr);
+        __ testptr(tmp, TypeEntries::type_klass_mask);
+        // klass seen before, nothing to do. The unknown bit may have been
+        // set already but no need to check.
+        __ jccb(Assembler::zero, next);
+
+        __ testptr(tmp, TypeEntries::type_unknown);
+        __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+
+        if (TypeEntries::is_type_none(current_klass)) {
+          __ cmpptr(mdo_addr, 0);
+          __ jccb(Assembler::equal, none);
+          __ cmpptr(mdo_addr, TypeEntries::null_seen);
+          __ jccb(Assembler::equal, none);
+          // There is a chance that the checks above (re-reading profiling
+          // data from memory) fail if another thread has just set the
+          // profiling to this obj's klass
+          __ xorptr(tmp, mdo_addr);
+          __ testptr(tmp, TypeEntries::type_klass_mask);
+          __ jccb(Assembler::zero, next);
+        }
+      } else {
+        assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
+               ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only");
+
+        __ movptr(tmp, mdo_addr);
+        __ testptr(tmp, TypeEntries::type_unknown);
+        __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+      }
+
+      // different than before. Cannot keep accurate profile.
+      __ orptr(mdo_addr, TypeEntries::type_unknown);
+
+      if (TypeEntries::is_type_none(current_klass)) {
+        __ jmpb(next);
+
+        __ bind(none);
+        // first time here. Set profile type.
+        __ movptr(mdo_addr, tmp);
+      }
+    } else {
+      // There's a single possible klass at this profile point
+      assert(exact_klass != NULL, "should be");
+      if (TypeEntries::is_type_none(current_klass)) {
+        __ mov_metadata(tmp, exact_klass->constant_encoding());
+        __ xorptr(tmp, mdo_addr);
+        __ testptr(tmp, TypeEntries::type_klass_mask);
+#ifdef ASSERT
+        __ jcc(Assembler::zero, next);
+
+        {
+          Label ok;
+          __ push(tmp);
+          __ cmpptr(mdo_addr, 0);
+          __ jcc(Assembler::equal, ok);
+          __ cmpptr(mdo_addr, TypeEntries::null_seen);
+          __ jcc(Assembler::equal, ok);
+          // may have been set by another thread
+          __ mov_metadata(tmp, exact_klass->constant_encoding());
+          __ xorptr(tmp, mdo_addr);
+          __ testptr(tmp, TypeEntries::type_mask);
+          __ jcc(Assembler::zero, ok);
+
+          __ stop("unexpected profiling mismatch");
+          __ bind(ok);
+          __ pop(tmp);
+        }
+#else
+        __ jccb(Assembler::zero, next);
+#endif
+        // first time here. Set profile type.
+        __ movptr(mdo_addr, tmp);
+      } else {
+        assert(ciTypeEntries::valid_ciklass(current_klass) != NULL &&
+               ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent");
+
+        __ movptr(tmp, mdo_addr);
+        __ testptr(tmp, TypeEntries::type_unknown);
+        __ jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+
+        __ orptr(mdo_addr, TypeEntries::type_unknown);
+      }
+    }
+
+    __ bind(next);
+  }
+}
+
 void LIR_Assembler::emit_delay(LIR_OpDelay*) {
   Unimplemented();
 }
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -79,6 +79,8 @@
 // GC Ergo Flags
 define_pd_global(uintx, CMSYoungGenPerWorker, 64*M);  // default max size of CMS young gen, per GC worker thread
 
+define_pd_global(uintx, TypeProfileLevel, 1);
+
 #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
                                                                             \
   develop(bool, IEEEPrecision, true,                                        \
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -1046,6 +1046,98 @@
   }
 }
 
+void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
+  Label update, next, none;
+
+  verify_oop(obj);
+
+  testptr(obj, obj);
+  jccb(Assembler::notZero, update);
+  orptr(mdo_addr, TypeEntries::null_seen);
+  jmpb(next);
+
+  bind(update);
+  load_klass(obj, obj);
+
+  xorptr(obj, mdo_addr);
+  testptr(obj, TypeEntries::type_klass_mask);
+  jccb(Assembler::zero, next); // klass seen before, nothing to
+                               // do. The unknown bit may have been
+                               // set already but no need to check.
+
+  testptr(obj, TypeEntries::type_unknown);
+  jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+
+  cmpptr(mdo_addr, 0);
+  jccb(Assembler::equal, none);
+  cmpptr(mdo_addr, TypeEntries::null_seen);
+  jccb(Assembler::equal, none);
+  // There is a chance that the checks above (re-reading profiling
+  // data from memory) fail if another thread has just set the
+  // profiling to this obj's klass
+  xorptr(obj, mdo_addr);
+  testptr(obj, TypeEntries::type_klass_mask);
+  jccb(Assembler::zero, next);
+
+  // different than before. Cannot keep accurate profile.
+  orptr(mdo_addr, TypeEntries::type_unknown);
+  jmpb(next);
+
+  bind(none);
+  // first time here. Set profile type.
+  movptr(mdo_addr, obj);
+
+  bind(next);
+}
+
+void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
+  if (!ProfileInterpreter) {
+    return;
+  }
+
+  if (MethodData::profile_arguments()) {
+    Label profile_continue;
+
+    test_method_data_pointer(mdp, profile_continue);
+
+    int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
+
+    cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
+    jcc(Assembler::notEqual, profile_continue);
+
+    Label done;
+    int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset());
+    addptr(mdp, off_to_args);
+
+    for (int i = 0; i < TypeProfileArgsLimit; i++) {
+      if (i > 0) {
+        movl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args));
+        subl(tmp, i*TypeStackSlotEntries::per_arg_count());
+        cmpl(tmp, TypeStackSlotEntries::per_arg_count());
+        jcc(Assembler::less, done);
+      }
+      movptr(tmp, Address(callee, Method::const_offset()));
+      load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
+      subl(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args));
+      subl(tmp, 1);
+      Address arg_addr = argument_address(tmp);
+      movptr(tmp, arg_addr);
+
+      Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args);
+      profile_obj_type(tmp, mdo_arg_addr);
+
+      int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
+      addptr(mdp, to_add);
+      off_to_args += to_add;
+    }
+
+    bind(done);
+
+    movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
+
+    bind(profile_continue);
+  }
+}
 
 void InterpreterMacroAssembler::profile_call(Register mdp) {
   if (ProfileInterpreter) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -215,6 +215,8 @@
 
   void profile_taken_branch(Register mdp, Register bumped_count);
   void profile_not_taken_branch(Register mdp);
+  void profile_obj_type(Register obj, const Address& mdo_addr);
+  void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
   void profile_call(Register mdp);
   void profile_final_call(Register mdp);
   void profile_virtual_call(Register receiver, Register mdp, Register scratch2,
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -1067,6 +1067,102 @@
   }
 }
 
+void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) {
+  Label update, next, none;
+
+  verify_oop(obj);
+
+  testptr(obj, obj);
+  jccb(Assembler::notZero, update);
+  orptr(mdo_addr, TypeEntries::null_seen);
+  jmpb(next);
+
+  bind(update);
+  load_klass(obj, obj);
+
+  xorptr(obj, mdo_addr);
+  testptr(obj, TypeEntries::type_klass_mask);
+  jccb(Assembler::zero, next); // klass seen before, nothing to
+                               // do. The unknown bit may have been
+                               // set already but no need to check.
+
+  testptr(obj, TypeEntries::type_unknown);
+  jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore.
+
+  // There is a chance that by the time we do these checks (re-reading
+  // profiling data from memory) another thread has set the profling
+  // to this obj's klass and we set the profiling as unknow
+  // erroneously
+  cmpptr(mdo_addr, 0);
+  jccb(Assembler::equal, none);
+  cmpptr(mdo_addr, TypeEntries::null_seen);
+  jccb(Assembler::equal, none);
+  // There is a chance that the checks above (re-reading profiling
+  // data from memory) fail if another thread has just set the
+  // profiling to this obj's klass
+  xorptr(obj, mdo_addr);
+  testptr(obj, TypeEntries::type_klass_mask);
+  jccb(Assembler::zero, next);
+
+  // different than before. Cannot keep accurate profile.
+  orptr(mdo_addr, TypeEntries::type_unknown);
+  jmpb(next);
+
+  bind(none);
+  // first time here. Set profile type.
+  movptr(mdo_addr, obj);
+
+  bind(next);
+}
+
+void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) {
+  if (!ProfileInterpreter) {
+    return;
+  }
+
+  if (MethodData::profile_arguments()) {
+    Label profile_continue;
+
+    test_method_data_pointer(mdp, profile_continue);
+
+    int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size());
+
+    cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag);
+    jcc(Assembler::notEqual, profile_continue);
+
+    Label done;
+    int off_to_args = in_bytes(TypeStackSlotEntries::args_data_offset());
+    addptr(mdp, off_to_args);
+
+    for (int i = 0; i < TypeProfileArgsLimit; i++) {
+      if (i > 0) {
+        movq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::cell_count_offset())-off_to_args));
+        subl(tmp, i*TypeStackSlotEntries::per_arg_count());
+        cmpl(tmp, TypeStackSlotEntries::per_arg_count());
+        jcc(Assembler::less, done);
+      }
+      movptr(tmp, Address(callee, Method::const_offset()));
+      load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset()));
+      subq(tmp, Address(mdp, in_bytes(TypeStackSlotEntries::stack_slot_offset(i))-off_to_args));
+      subl(tmp, 1);
+      Address arg_addr = argument_address(tmp);
+      movptr(tmp, arg_addr);
+
+      Address mdo_arg_addr(mdp, in_bytes(TypeStackSlotEntries::type_offset(i))-off_to_args);
+      profile_obj_type(tmp, mdo_arg_addr);
+
+      int to_add = in_bytes(TypeStackSlotEntries::per_arg_size());
+      addptr(mdp, to_add);
+      off_to_args += to_add;
+    }
+
+    bind(done);
+
+    movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp);
+
+    bind(profile_continue);
+  }
+}
 
 void InterpreterMacroAssembler::profile_call(Register mdp) {
   if (ProfileInterpreter) {
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -224,6 +224,8 @@
 
   void profile_taken_branch(Register mdp, Register bumped_count);
   void profile_not_taken_branch(Register mdp);
+  void profile_obj_type(Register obj, const Address& mdo_addr);
+  void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual);
   void profile_call(Register mdp);
   void profile_final_call(Register mdp);
   void profile_virtual_call(Register receiver, Register mdp,
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -773,6 +773,7 @@
   void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
   void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
   void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
+  void orptr(Address dst, int32_t imm32) { LP64_ONLY(orq(dst, imm32)) NOT_LP64(orl(dst, imm32)); }
 
   void testptr(Register src, int32_t imm32) {  LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
   void testptr(Register src1, Register src2);
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -2970,6 +2970,7 @@
 
   // profile this call
   __ profile_final_call(rax);
+  __ profile_arguments_type(rax, method, rsi, true);
 
   __ jump_from_interpreted(method, rax);
 
@@ -2984,6 +2985,7 @@
 
   // get target Method* & entry point
   __ lookup_virtual_method(rax, index, method);
+  __ profile_arguments_type(rdx, method, rsi, true);
   __ jump_from_interpreted(method, rdx);
 }
 
@@ -3013,6 +3015,7 @@
   __ null_check(rcx);
   // do the call
   __ profile_call(rax);
+  __ profile_arguments_type(rax, rbx, rsi, false);
   __ jump_from_interpreted(rbx, rax);
 }
 
@@ -3023,6 +3026,7 @@
   prepare_invoke(byte_no, rbx);  // get f1 Method*
   // do the call
   __ profile_call(rax);
+  __ profile_arguments_type(rax, rbx, rsi, false);
   __ jump_from_interpreted(rbx, rax);
 }
 
@@ -3082,6 +3086,8 @@
   __ testptr(rbx, rbx);
   __ jcc(Assembler::zero, no_such_method);
 
+  __ profile_arguments_type(rdx, rbx, rsi, true);
+
   // do the call
   // rcx: receiver
   // rbx,: Method*
@@ -3138,6 +3144,7 @@
 
   // FIXME: profile the LambdaForm also
   __ profile_final_call(rax);
+  __ profile_arguments_type(rdx, rbx_method, rsi, true);
 
   __ jump_from_interpreted(rbx_method, rdx);
 }
@@ -3171,6 +3178,7 @@
   // %%% should make a type profile for any invokedynamic that takes a ref argument
   // profile this call
   __ profile_call(rsi);
+  __ profile_arguments_type(rdx, rbx, rsi, false);
 
   __ verify_oop(rax_callsite);
 
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -3026,6 +3026,7 @@
 
   // profile this call
   __ profile_final_call(rax);
+  __ profile_arguments_type(rax, method, r13, true);
 
   __ jump_from_interpreted(method, rax);
 
@@ -3040,6 +3041,7 @@
 
   // get target Method* & entry point
   __ lookup_virtual_method(rax, index, method);
+  __ profile_arguments_type(rdx, method, r13, true);
   __ jump_from_interpreted(method, rdx);
 }
 
@@ -3069,6 +3071,7 @@
   __ null_check(rcx);
   // do the call
   __ profile_call(rax);
+  __ profile_arguments_type(rax, rbx, r13, false);
   __ jump_from_interpreted(rbx, rax);
 }
 
@@ -3079,6 +3082,7 @@
   prepare_invoke(byte_no, rbx);  // get f1 Method*
   // do the call
   __ profile_call(rax);
+  __ profile_arguments_type(rax, rbx, r13, false);
   __ jump_from_interpreted(rbx, rax);
 }
 
@@ -3136,6 +3140,8 @@
   __ testptr(rbx, rbx);
   __ jcc(Assembler::zero, no_such_method);
 
+  __ profile_arguments_type(rdx, rbx, r13, true);
+
   // do the call
   // rcx: receiver
   // rbx,: Method*
@@ -3193,6 +3199,7 @@
 
   // FIXME: profile the LambdaForm also
   __ profile_final_call(rax);
+  __ profile_arguments_type(rdx, rbx_method, r13, true);
 
   __ jump_from_interpreted(rbx_method, rdx);
 }
@@ -3226,6 +3233,7 @@
   // %%% should make a type profile for any invokedynamic that takes a ref argument
   // profile this call
   __ profile_call(r13);
+  __ profile_arguments_type(rdx, rbx_method, r13, false);
 
   __ verify_oop(rax_callsite);
 
--- a/hotspot/src/share/vm/c1/c1_Compilation.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -601,6 +601,17 @@
   }
 }
 
+ciKlass* Compilation::cha_exact_type(ciType* type) {
+  if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
+    ciInstanceKlass* ik = type->as_instance_klass();
+    assert(ik->exact_klass() == NULL, "no cha for final klass");
+    if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
+      dependency_recorder()->assert_leaf_type(ik);
+      return ik;
+    }
+  }
+  return NULL;
+}
 
 void Compilation::print_timers() {
   // tty->print_cr("    Native methods         : %6.3f s, Average : %2.3f", CompileBroker::_t_native_compilation.seconds(), CompileBroker::_t_native_compilation.seconds() / CompileBroker::_total_native_compile_count);
--- a/hotspot/src/share/vm/c1/c1_Compilation.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -246,6 +246,8 @@
       (RangeCheckElimination || UseLoopInvariantCodeMotion) &&
       method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
   }
+
+  ciKlass* cha_exact_type(ciType* type);
 };
 
 
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -1658,6 +1658,42 @@
   return compilation()->dependency_recorder();
 }
 
+// How many arguments do we want to profile?
+Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) {
+  int n = 0;
+  assert(start == 0, "should be initialized");
+  if (MethodData::profile_arguments()) {
+    ciProfileData* data = method()->method_data()->bci_to_data(bci());
+    if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
+      n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments();
+      bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
+      start = has_receiver ? 1 : 0;
+    }
+  }
+  if (n > 0) {
+    return new Values(n);
+  }
+  return NULL;
+}
+
+// Collect arguments that we want to profile in a list
+Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) {
+  int start = 0;
+  Values* obj_args = args_list_for_profiling(start, may_have_receiver);
+  if (obj_args == NULL) {
+    return NULL;
+  }
+  int s = obj_args->size();
+  for (int i = start, j = 0; j < s; i++) {
+    if (args->at(i)->type()->is_object_kind()) {
+      obj_args->push(args->at(i));
+      j++;
+    }
+  }
+  assert(s == obj_args->length(), "missed on arg?");
+  return obj_args;
+}
+
 
 void GraphBuilder::invoke(Bytecodes::Code code) {
   bool will_link;
@@ -1957,7 +1993,7 @@
       } else if (exact_target != NULL) {
         target_klass = exact_target->holder();
       }
-      profile_call(target, recv, target_klass);
+      profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false);
     }
   }
 
@@ -3509,7 +3545,7 @@
           recv = args->at(0);
           null_check(recv);
         }
-        profile_call(callee, recv, NULL);
+        profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true);
       }
     }
   }
@@ -3763,7 +3799,28 @@
     compilation()->set_would_profile(true);
 
     if (profile_calls()) {
-      profile_call(callee, recv, holder_known ? callee->holder() : NULL);
+      int start = 0;
+      Values* obj_args = args_list_for_profiling(start, has_receiver);
+      if (obj_args != NULL) {
+        int s = obj_args->size();
+        // if called through method handle invoke, some arguments may have been popped
+        for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) {
+          Value v = state()->stack_at_inc(i);
+          if (v->type()->is_object_kind()) {
+            obj_args->push(v);
+            j++;
+          }
+        }
+#ifdef ASSERT
+        {
+          bool ignored_will_link;
+          ciSignature* declared_signature = NULL;
+          ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
+          assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
+        }
+#endif
+      }
+      profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true);
     }
   }
 
@@ -4251,8 +4308,8 @@
 }
 #endif // PRODUCT
 
-void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) {
-  append(new ProfileCall(method(), bci(), callee, recv, known_holder));
+void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) {
+  append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined));
 }
 
 void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -374,7 +374,7 @@
 
   void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true);
 
-  void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder);
+  void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined);
   void profile_invocation(ciMethod* inlinee, ValueStack* state);
 
   // Shortcuts to profiling control.
@@ -386,6 +386,9 @@
   bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
   bool profile_checkcasts()    { return _compilation->profile_checkcasts();    }
 
+  Values* args_list_for_profiling(int& start, bool may_have_receiver);
+  Values* collect_args_for_profiling(Values* args, bool may_have_receiver);
+
  public:
   NOT_PRODUCT(void print_stats();)
 
--- a/hotspot/src/share/vm/c1/c1_Instruction.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_Instruction.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -104,6 +104,14 @@
   }
 }
 
+ciType* Instruction::exact_type() const {
+  ciType* t =  declared_type();
+  if (t != NULL && t->is_klass()) {
+    return t->as_klass()->exact_klass();
+  }
+  return NULL;
+}
+
 
 #ifndef PRODUCT
 void Instruction::check_state(ValueStack* state) {
@@ -135,9 +143,7 @@
 
 // perform constant and interval tests on index value
 bool AccessIndexed::compute_needs_range_check() {
-
   if (length()) {
-
     Constant* clength = length()->as_Constant();
     Constant* cindex = index()->as_Constant();
     if (clength && cindex) {
@@ -157,34 +163,8 @@
 }
 
 
-ciType* Local::exact_type() const {
-  ciType* type = declared_type();
-
-  // for primitive arrays, the declared type is the exact type
-  if (type->is_type_array_klass()) {
-    return type;
-  } else if (type->is_instance_klass()) {
-    ciInstanceKlass* ik = (ciInstanceKlass*)type;
-    if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) {
-      return type;
-    }
-  } else if (type->is_obj_array_klass()) {
-    ciObjArrayKlass* oak = (ciObjArrayKlass*)type;
-    ciType* base = oak->base_element_type();
-    if (base->is_instance_klass()) {
-      ciInstanceKlass* ik = base->as_instance_klass();
-      if (ik->is_loaded() && ik->is_final()) {
-        return type;
-      }
-    } else if (base->is_primitive_type()) {
-      return type;
-    }
-  }
-  return NULL;
-}
-
 ciType* Constant::exact_type() const {
-  if (type()->is_object()) {
+  if (type()->is_object() && type()->as_ObjectType()->is_loaded()) {
     return type()->as_ObjectType()->exact_type();
   }
   return NULL;
@@ -192,19 +172,18 @@
 
 ciType* LoadIndexed::exact_type() const {
   ciType* array_type = array()->exact_type();
-  if (array_type == NULL) {
-    return NULL;
-  }
-  assert(array_type->is_array_klass(), "what else?");
-  ciArrayKlass* ak = (ciArrayKlass*)array_type;
+  if (array_type != NULL) {
+    assert(array_type->is_array_klass(), "what else?");
+    ciArrayKlass* ak = (ciArrayKlass*)array_type;
 
-  if (ak->element_type()->is_instance_klass()) {
-    ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
-    if (ik->is_loaded() && ik->is_final()) {
-      return ik;
+    if (ak->element_type()->is_instance_klass()) {
+      ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
+      if (ik->is_loaded() && ik->is_final()) {
+        return ik;
+      }
     }
   }
-  return NULL;
+  return Instruction::exact_type();
 }
 
 
@@ -224,22 +203,6 @@
 }
 
 
-ciType* LoadField::exact_type() const {
-  ciType* type = declared_type();
-  // for primitive arrays, the declared type is the exact type
-  if (type->is_type_array_klass()) {
-    return type;
-  }
-  if (type->is_instance_klass()) {
-    ciInstanceKlass* ik = (ciInstanceKlass*)type;
-    if (ik->is_loaded() && ik->is_final()) {
-      return type;
-    }
-  }
-  return NULL;
-}
-
-
 ciType* NewTypeArray::exact_type() const {
   return ciTypeArrayKlass::make(elt_type());
 }
@@ -264,16 +227,6 @@
   return klass();
 }
 
-ciType* CheckCast::exact_type() const {
-  if (klass()->is_instance_klass()) {
-    ciInstanceKlass* ik = (ciInstanceKlass*)klass();
-    if (ik->is_loaded() && ik->is_final()) {
-      return ik;
-    }
-  }
-  return NULL;
-}
-
 // Implementation of ArithmeticOp
 
 bool ArithmeticOp::is_commutative() const {
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -322,6 +322,36 @@
     _type = type;
   }
 
+  // Helper class to keep track of which arguments need a null check
+  class ArgsNonNullState {
+  private:
+    int _nonnull_state; // mask identifying which args are nonnull
+  public:
+    ArgsNonNullState()
+      : _nonnull_state(AllBits) {}
+
+    // Does argument number i needs a null check?
+    bool arg_needs_null_check(int i) const {
+      // No data is kept for arguments starting at position 33 so
+      // conservatively assume that they need a null check.
+      if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
+        return is_set_nth_bit(_nonnull_state, i);
+      }
+      return true;
+    }
+
+    // Set whether argument number i needs a null check or not
+    void set_arg_needs_null_check(int i, bool check) {
+      if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
+        if (check) {
+          _nonnull_state |= nth_bit(i);
+        } else {
+          _nonnull_state &= ~(nth_bit(i));
+        }
+      }
+    }
+  };
+
  public:
   void* operator new(size_t size) throw() {
     Compilation* c = Compilation::current();
@@ -566,7 +596,7 @@
   virtual void other_values_do(ValueVisitor* f)   { /* usually no other - override on demand */ }
           void       values_do(ValueVisitor* f)   { input_values_do(f); state_values_do(f); other_values_do(f); }
 
-  virtual ciType* exact_type() const             { return NULL; }
+  virtual ciType* exact_type() const;
   virtual ciType* declared_type() const          { return NULL; }
 
   // hashing
@@ -689,7 +719,6 @@
   int java_index() const                         { return _java_index; }
 
   virtual ciType* declared_type() const          { return _declared_type; }
-  virtual ciType* exact_type() const;
 
   // generic
   virtual void input_values_do(ValueVisitor* f)   { /* no values */ }
@@ -806,7 +835,6 @@
   {}
 
   ciType* declared_type() const;
-  ciType* exact_type() const;
 
   // generic
   HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset())  // cannot be eliminated if needs patching or if volatile
@@ -1299,6 +1327,7 @@
 
   virtual bool needs_exception_state() const     { return false; }
 
+  ciType* exact_type() const                     { return NULL; }
   ciType* declared_type() const;
 
   // generic
@@ -1422,7 +1451,6 @@
   }
 
   ciType* declared_type() const;
-  ciType* exact_type() const;
 };
 
 
@@ -1490,7 +1518,7 @@
   vmIntrinsics::ID _id;
   Values*          _args;
   Value            _recv;
-  int              _nonnull_state; // mask identifying which args are nonnull
+  ArgsNonNullState _nonnull_state;
 
  public:
   // preserves_state can be set to true for Intrinsics
@@ -1511,7 +1539,6 @@
   , _id(id)
   , _args(args)
   , _recv(NULL)
-  , _nonnull_state(AllBits)
   {
     assert(args != NULL, "args must exist");
     ASSERT_VALUES
@@ -1537,21 +1564,12 @@
   Value receiver() const                         { assert(has_receiver(), "must have receiver"); return _recv; }
   bool preserves_state() const                   { return check_flag(PreservesStateFlag); }
 
-  bool arg_needs_null_check(int i) {
-    if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
-      return is_set_nth_bit(_nonnull_state, i);
-    }
-    return true;
+  bool arg_needs_null_check(int i) const {
+    return _nonnull_state.arg_needs_null_check(i);
   }
 
   void set_arg_needs_null_check(int i, bool check) {
-    if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
-      if (check) {
-        _nonnull_state |= nth_bit(i);
-      } else {
-        _nonnull_state &= ~(nth_bit(i));
-      }
-    }
+    _nonnull_state.set_arg_needs_null_check(i, check);
   }
 
   // generic
@@ -2450,35 +2468,56 @@
 
 LEAF(ProfileCall, Instruction)
  private:
-  ciMethod* _method;
-  int       _bci_of_invoke;
-  ciMethod* _callee;         // the method that is called at the given bci
-  Value     _recv;
-  ciKlass*  _known_holder;
+  ciMethod*        _method;
+  int              _bci_of_invoke;
+  ciMethod*        _callee;         // the method that is called at the given bci
+  Value            _recv;
+  ciKlass*         _known_holder;
+  Values*          _obj_args;       // arguments for type profiling
+  ArgsNonNullState _nonnull_state;  // Do we know whether some arguments are never null?
+  bool             _inlined;        // Are we profiling a call that is inlined
 
  public:
-  ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder)
+  ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined)
     : Instruction(voidType)
     , _method(method)
     , _bci_of_invoke(bci)
     , _callee(callee)
     , _recv(recv)
     , _known_holder(known_holder)
+    , _obj_args(obj_args)
+    , _inlined(inlined)
   {
     // The ProfileCall has side-effects and must occur precisely where located
     pin();
   }
 
-  ciMethod* method()      { return _method; }
-  int bci_of_invoke()     { return _bci_of_invoke; }
-  ciMethod* callee()      { return _callee; }
-  Value recv()            { return _recv; }
-  ciKlass* known_holder() { return _known_holder; }
-
-  virtual void input_values_do(ValueVisitor* f)   { if (_recv != NULL) f->visit(&_recv); }
+  ciMethod* method()             const { return _method; }
+  int bci_of_invoke()            const { return _bci_of_invoke; }
+  ciMethod* callee()             const { return _callee; }
+  Value recv()                   const { return _recv; }
+  ciKlass* known_holder()        const { return _known_holder; }
+  int nb_profiled_args()         const { return _obj_args == NULL ? 0 : _obj_args->length(); }
+  Value profiled_arg_at(int i)   const { return _obj_args->at(i); }
+  bool arg_needs_null_check(int i) const {
+    return _nonnull_state.arg_needs_null_check(i);
+  }
+  bool inlined()                 const { return _inlined; }
+
+  void set_arg_needs_null_check(int i, bool check) {
+    _nonnull_state.set_arg_needs_null_check(i, check);
+  }
+
+  virtual void input_values_do(ValueVisitor* f)   {
+    if (_recv != NULL) {
+      f->visit(&_recv);
+    }
+    for (int i = 0; i < nb_profiled_args(); i++) {
+      f->visit(_obj_args->adr_at(i));
+    }
+  }
 };
 
-
 // Call some C runtime function that doesn't safepoint,
 // optionally passing the current thread as the first argument.
 LEAF(RuntimeCall, Instruction)
--- a/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_InstructionPrinter.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -892,6 +892,14 @@
   if (x->known_holder() != NULL) {
     output()->print(", ");
     print_klass(x->known_holder());
+    output()->print(" ");
+  }
+  for (int i = 0; i < x->nb_profiled_args(); i++) {
+    if (i > 0) output()->print(", ");
+    print_value(x->profiled_arg_at(i));
+    if (x->arg_needs_null_check(i)) {
+      output()->print(" [NC]");
+    }
   }
   output()->put(')');
 }
--- a/hotspot/src/share/vm/c1/c1_LIR.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIR.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -1001,6 +1001,17 @@
       assert(opProfileCall->_tmp1->is_valid(), "used");  do_temp(opProfileCall->_tmp1);
       break;
     }
+
+// LIR_OpProfileType:
+    case lir_profile_type: {
+      assert(op->as_OpProfileType() != NULL, "must be");
+      LIR_OpProfileType* opProfileType = (LIR_OpProfileType*)op;
+
+      do_input(opProfileType->_mdp); do_temp(opProfileType->_mdp);
+      do_input(opProfileType->_obj);
+      do_temp(opProfileType->_tmp);
+      break;
+    }
   default:
     ShouldNotReachHere();
   }
@@ -1151,6 +1162,10 @@
   masm->emit_profile_call(this);
 }
 
+void LIR_OpProfileType::emit_code(LIR_Assembler* masm) {
+  masm->emit_profile_type(this);
+}
+
 // LIR_List
 LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
   : _operations(8)
@@ -1803,6 +1818,8 @@
      case lir_cas_int:               s = "cas_int";      break;
      // LIR_OpProfileCall
      case lir_profile_call:          s = "profile_call";  break;
+     // LIR_OpProfileType
+     case lir_profile_type:          s = "profile_type";  break;
      // LIR_OpAssert
 #ifdef ASSERT
      case lir_assert:                s = "assert";        break;
@@ -2086,6 +2103,15 @@
   tmp1()->print(out);          out->print(" ");
 }
 
+// LIR_OpProfileType
+void LIR_OpProfileType::print_instr(outputStream* out) const {
+  out->print("exact = "); exact_klass()->print_name_on(out);
+  out->print("current = "); ciTypeEntries::print_ciklass(out, current_klass());
+  mdp()->print(out);          out->print(" ");
+  obj()->print(out);          out->print(" ");
+  tmp()->print(out);          out->print(" ");
+}
+
 #endif // PRODUCT
 
 // Implementation of LIR_InsertionBuffer
--- a/hotspot/src/share/vm/c1/c1_LIR.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIR.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -882,6 +882,7 @@
 class    LIR_OpTypeCheck;
 class    LIR_OpCompareAndSwap;
 class    LIR_OpProfileCall;
+class    LIR_OpProfileType;
 #ifdef ASSERT
 class    LIR_OpAssert;
 #endif
@@ -1005,6 +1006,7 @@
   , end_opCompareAndSwap
   , begin_opMDOProfile
     , lir_profile_call
+    , lir_profile_type
   , end_opMDOProfile
   , begin_opAssert
     , lir_assert
@@ -1145,6 +1147,7 @@
   virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
   virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
   virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
+  virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
 #ifdef ASSERT
   virtual LIR_OpAssert* as_OpAssert() { return NULL; }
 #endif
@@ -1925,8 +1928,8 @@
 
  public:
   // Destroys recv
-  LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
-    : LIR_Op(code, LIR_OprFact::illegalOpr, NULL)  // no result, no info
+  LIR_OpProfileCall(ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
+    : LIR_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL)  // no result, no info
     , _profiled_method(profiled_method)
     , _profiled_bci(profiled_bci)
     , _profiled_callee(profiled_callee)
@@ -1948,6 +1951,45 @@
   virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
 };
 
+// LIR_OpProfileType
+class LIR_OpProfileType : public LIR_Op {
+ friend class LIR_OpVisitState;
+
+ private:
+  LIR_Opr      _mdp;
+  LIR_Opr      _obj;
+  LIR_Opr      _tmp;
+  ciKlass*     _exact_klass;   // non NULL if we know the klass statically (no need to load it from _obj)
+  intptr_t     _current_klass; // what the profiling currently reports
+  bool         _not_null;      // true if we know statically that _obj cannot be null
+  bool         _no_conflict;   // true if we're profling parameters, _exact_klass is not NULL and we know
+                               // _exact_klass it the only possible type for this parameter in any context.
+
+ public:
+  // Destroys recv
+  LIR_OpProfileType(LIR_Opr mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict)
+    : LIR_Op(lir_profile_type, LIR_OprFact::illegalOpr, NULL)  // no result, no info
+    , _mdp(mdp)
+    , _obj(obj)
+    , _exact_klass(exact_klass)
+    , _current_klass(current_klass)
+    , _tmp(tmp)
+    , _not_null(not_null)
+    , _no_conflict(no_conflict) { }
+
+  LIR_Opr      mdp()              const             { return _mdp;              }
+  LIR_Opr      obj()              const             { return _obj;              }
+  LIR_Opr      tmp()              const             { return _tmp;              }
+  ciKlass*     exact_klass()      const             { return _exact_klass;      }
+  intptr_t     current_klass()    const             { return _current_klass;    }
+  bool         not_null()         const             { return _not_null;         }
+  bool         no_conflict()      const             { return _no_conflict;      }
+
+  virtual void emit_code(LIR_Assembler* masm);
+  virtual LIR_OpProfileType* as_OpProfileType() { return this; }
+  virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
+};
+
 class LIR_InsertionBuffer;
 
 //--------------------------------LIR_List---------------------------------------------------
@@ -2247,7 +2289,10 @@
                   ciMethod* profiled_method, int profiled_bci);
   // MethodData* profiling
   void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) {
-    append(new LIR_OpProfileCall(lir_profile_call, method, bci, callee, mdo, recv, t1, cha_klass));
+    append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass));
+  }
+  void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) {
+    append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict));
   }
 
   void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); }
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -208,6 +208,7 @@
   void emit_call(LIR_OpJavaCall* op);
   void emit_rtcall(LIR_OpRTCall* op);
   void emit_profile_call(LIR_OpProfileCall* op);
+  void emit_profile_type(LIR_OpProfileType* op);
   void emit_delay(LIR_OpDelay* op);
 
   void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -2571,6 +2571,78 @@
 }
 
 
+ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) {
+  ciKlass* result = NULL;
+  bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k);
+  bool do_update = !TypeEntries::is_type_unknown(profiled_k);
+  // known not to be null or null bit already set and already set to
+  // unknown: nothing we can do to improve profiling
+  if (!do_null && !do_update) {
+    return result;
+  }
+
+  ciKlass* exact_klass = NULL;
+  Compilation* comp = Compilation::current();
+  if (do_update) {
+    // try to find exact type, using CHA if possible, so that loading
+    // the klass from the object can be avoided
+    ciType* type = arg->exact_type();
+    if (type == NULL) {
+      type = arg->declared_type();
+      type = comp->cha_exact_type(type);
+    }
+    assert(type == NULL || type->is_klass(), "type should be class");
+    exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL;
+
+    do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
+  }
+
+  if (!do_null && !do_update) {
+    return result;
+  }
+
+  ciKlass* exact_signature_k = NULL;
+  if (do_update) {
+    // Is the type from the signature exact (the only one possible)?
+    exact_signature_k = signature_k->exact_klass();
+    if (exact_signature_k == NULL) {
+      exact_signature_k = comp->cha_exact_type(signature_k);
+    } else {
+      result = exact_signature_k;
+      do_update = false;
+      // Known statically. No need to emit any code: prevent
+      // LIR_Assembler::emit_profile_type() from emitting useless code
+      profiled_k = ciTypeEntries::with_status(result, profiled_k);
+    }
+    if (exact_signature_k != NULL && exact_klass != exact_signature_k) {
+      assert(exact_klass == NULL, "arg and signature disagree?");
+      // sometimes the type of the signature is better than the best type
+      // the compiler has
+      exact_klass = exact_signature_k;
+      do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
+    }
+  }
+
+  if (!do_null && !do_update) {
+    return result;
+  }
+
+  if (mdp == LIR_OprFact::illegalOpr) {
+    mdp = new_register(T_METADATA);
+    __ metadata2reg(md->constant_encoding(), mdp);
+    if (md_base_offset != 0) {
+      LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS);
+      mdp = new_pointer_register();
+      __ leal(LIR_OprFact::address(base_type_address), mdp);
+    }
+  }
+  LIRItem value(arg, this);
+  value.load_item();
+  __ profile_type(new LIR_Address(mdp, md_offset, T_METADATA),
+                  value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL);
+  return result;
+}
+
 void LIRGenerator::do_Base(Base* x) {
   __ std_entry(LIR_OprFact::illegalOpr);
   // Emit moves from physical registers / stack slots to virtual registers
@@ -3004,12 +3076,52 @@
   }
 }
 
+void LIRGenerator::profile_arguments(ProfileCall* x) {
+  if (MethodData::profile_arguments()) {
+    int bci = x->bci_of_invoke();
+    ciMethodData* md = x->method()->method_data_or_null();
+    ciProfileData* data = md->bci_to_data(bci);
+    if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
+      ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
+      int base_offset = md->byte_offset_of_slot(data, extra);
+      LIR_Opr mdp = LIR_OprFact::illegalOpr;
+      ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args();
+
+      Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
+      int start = 0;
+      int stop = args->number_of_arguments();
+      if (x->nb_profiled_args() < stop) {
+        // if called through method handle invoke, some arguments may have been popped
+        stop = x->nb_profiled_args();
+      }
+      ciSignature* sig = x->callee()->signature();
+      // method handle call to virtual method
+      bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc);
+      ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL);
+      for (int i = 0; i < stop; i++) {
+        int off = in_bytes(TypeStackSlotEntries::type_offset(i)) - in_bytes(TypeStackSlotEntries::args_data_offset());
+        ciKlass* exact = profile_arg_type(md, base_offset, off,
+                                          args->type(i), x->profiled_arg_at(i+start), mdp,
+                                          !x->arg_needs_null_check(i+start), sig_stream.next_klass());
+        if (exact != NULL) {
+          md->set_argument_type(bci, i, exact);
+        }
+      }
+    }
+  }
+}
+
 void LIRGenerator::do_ProfileCall(ProfileCall* x) {
   // Need recv in a temporary register so it interferes with the other temporaries
   LIR_Opr recv = LIR_OprFact::illegalOpr;
   LIR_Opr mdo = new_register(T_OBJECT);
   // tmp is used to hold the counters on SPARC
   LIR_Opr tmp = new_pointer_register();
+
+  if (x->nb_profiled_args() > 0) {
+    profile_arguments(x);
+  }
+
   if (x->recv() != NULL) {
     LIRItem value(x->recv(), this);
     value.load_item();
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -434,6 +434,8 @@
   void do_ThreadIDIntrinsic(Intrinsic* x);
   void do_ClassIDIntrinsic(Intrinsic* x);
 #endif
+  ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k);
+  void profile_arguments(ProfileCall* x);
 
  public:
   Compilation*  compilation() const              { return _compilation; }
--- a/hotspot/src/share/vm/c1/c1_Optimizer.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_Optimizer.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -657,6 +657,7 @@
   void handle_Intrinsic       (Intrinsic* x);
   void handle_ExceptionObject (ExceptionObject* x);
   void handle_Phi             (Phi* x);
+  void handle_ProfileCall     (ProfileCall* x);
 };
 
 
@@ -715,7 +716,8 @@
 void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
 void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead*  x) {}
 void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {}
-void NullCheckVisitor::do_ProfileCall    (ProfileCall*     x) { nce()->clear_last_explicit_null_check(); }
+void NullCheckVisitor::do_ProfileCall    (ProfileCall*     x) { nce()->clear_last_explicit_null_check();
+                                                                nce()->handle_ProfileCall(x); }
 void NullCheckVisitor::do_ProfileInvoke  (ProfileInvoke*   x) {}
 void NullCheckVisitor::do_RuntimeCall    (RuntimeCall*     x) {}
 void NullCheckVisitor::do_MemBar         (MemBar*          x) {}
@@ -1134,6 +1136,11 @@
   }
 }
 
+void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) {
+  for (int i = 0; i < x->nb_profiled_args(); i++) {
+    x->set_arg_needs_null_check(i, !set_contains(x->profiled_arg_at(i)));
+  }
+}
 
 void Optimizer::eliminate_null_checks() {
   ResourceMark rm;
--- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -162,7 +162,7 @@
     void do_UnsafePrefetchRead (UnsafePrefetchRead*  x) { /* nothing to do */ };
     void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ };
     void do_ProfileCall    (ProfileCall*     x) { /* nothing to do */ };
-    void do_ProfileInvoke  (ProfileInvoke*  x)  { /* nothing to do */ };
+    void do_ProfileInvoke  (ProfileInvoke*   x) { /* nothing to do */ };
     void do_RuntimeCall    (RuntimeCall*     x) { /* nothing to do */ };
     void do_MemBar         (MemBar*          x) { /* nothing to do */ };
     void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
--- a/hotspot/src/share/vm/ci/ciClassList.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciClassList.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -102,6 +102,7 @@
 friend class ciMethodHandle;           \
 friend class ciMethodType;             \
 friend class ciReceiverTypeData;       \
+friend class ciTypeEntries;            \
 friend class ciSymbol;                 \
 friend class ciArray;                  \
 friend class ciObjArray;               \
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -235,6 +235,13 @@
   bool is_instance_klass() const { return true; }
   bool is_java_klass() const     { return true; }
 
+  virtual ciKlass* exact_klass() {
+    if (is_loaded() && is_final() && !is_interface()) {
+      return this;
+    }
+    return NULL;
+  }
+
   // Dump the current state of this klass for compilation replay.
   virtual void dump_replay_data(outputStream* out);
 };
--- a/hotspot/src/share/vm/ci/ciKlass.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciKlass.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -41,6 +41,7 @@
   friend class ciEnv;
   friend class ciField;
   friend class ciMethod;
+  friend class ciMethodData;
   friend class ciObjArrayKlass;
 
 private:
@@ -121,6 +122,8 @@
   // What kind of ciObject is this?
   bool is_klass() const { return true; }
 
+  virtual ciKlass* exact_klass() = 0;
+
   void print_name_on(outputStream* st);
 };
 
--- a/hotspot/src/share/vm/ci/ciMethodData.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodData.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -125,7 +125,7 @@
 #endif
 }
 
-void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
+void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) {
   for (uint row = 0; row < row_limit(); row++) {
     Klass* k = data->as_ReceiverTypeData()->receiver(row);
     if (k != NULL) {
@@ -136,6 +136,13 @@
 }
 
 
+void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) {
+  for (int i = 0; i < number_of_arguments(); i++) {
+    intptr_t k = entries->type(i);
+    TypeStackSlotEntries::set_type(i, translate_klass(k));
+  }
+}
+
 // Get the data at an arbitrary (sort of) data index.
 ciProfileData* ciMethodData::data_at(int data_index) {
   if (out_of_bounds(data_index)) {
@@ -166,6 +173,10 @@
     return new ciMultiBranchData(data_layout);
   case DataLayout::arg_info_data_tag:
     return new ciArgInfoData(data_layout);
+  case DataLayout::call_type_data_tag:
+    return new ciCallTypeData(data_layout);
+  case DataLayout::virtual_call_type_data_tag:
+    return new ciVirtualCallTypeData(data_layout);
   };
 }
 
@@ -288,6 +299,20 @@
   }
 }
 
+void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) {
+  VM_ENTRY_MARK;
+  MethodData* mdo = get_MethodData();
+  if (mdo != NULL) {
+    ProfileData* data = mdo->bci_to_data(bci);
+    if (data->is_CallTypeData()) {
+      data->as_CallTypeData()->set_argument_type(i, k->get_Klass());
+    } else {
+      assert(data->is_VirtualCallTypeData(), "no arguments!");
+      data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass());
+    }
+  }
+}
+
 bool ciMethodData::has_escape_info() {
   return eflag_set(MethodData::estimated);
 }
@@ -478,7 +503,36 @@
   }
 }
 
-void ciReceiverTypeData::print_receiver_data_on(outputStream* st) {
+void ciTypeEntries::print_ciklass(outputStream* st, intptr_t k) {
+  if (TypeEntries::is_type_none(k)) {
+    st->print("none");
+  } else if (TypeEntries::is_type_unknown(k)) {
+    st->print("unknown");
+  } else {
+    valid_ciklass(k)->print_name_on(st);
+  }
+  if (TypeEntries::was_null_seen(k)) {
+    st->print(" (null seen)");
+  }
+}
+
+void ciTypeStackSlotEntries::print_data_on(outputStream* st) const {
+  _pd->tab(st, true);
+  st->print("argument types");
+  for (int i = 0; i < number_of_arguments(); i++) {
+    _pd->tab(st);
+    st->print("%d: stack (%u) ", i, stack_slot(i));
+    print_ciklass(st, type(i));
+    st->cr();
+  }
+}
+
+void ciCallTypeData::print_data_on(outputStream* st) const {
+  print_shared(st, "ciCallTypeData");
+  args()->print_data_on(st);
+}
+
+void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
   uint row;
   int entries = 0;
   for (row = 0; row < row_limit(); row++) {
@@ -494,13 +548,19 @@
   }
 }
 
-void ciReceiverTypeData::print_data_on(outputStream* st) {
+void ciReceiverTypeData::print_data_on(outputStream* st) const {
   print_shared(st, "ciReceiverTypeData");
   print_receiver_data_on(st);
 }
 
-void ciVirtualCallData::print_data_on(outputStream* st) {
+void ciVirtualCallData::print_data_on(outputStream* st) const {
   print_shared(st, "ciVirtualCallData");
   rtd_super()->print_receiver_data_on(st);
 }
+
+void ciVirtualCallTypeData::print_data_on(outputStream* st) const {
+  print_shared(st, "ciVirtualCallTypeData");
+  rtd_super()->print_receiver_data_on(st);
+  args()->print_data_on(st);
+}
 #endif
--- a/hotspot/src/share/vm/ci/ciMethodData.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodData.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -41,6 +41,8 @@
 class ciArrayData;
 class ciMultiBranchData;
 class ciArgInfoData;
+class ciCallTypeData;
+class ciVirtualCallTypeData;
 
 typedef ProfileData ciProfileData;
 
@@ -59,6 +61,68 @@
   ciJumpData(DataLayout* layout) : JumpData(layout) {};
 };
 
+class ciTypeEntries {
+protected:
+  static intptr_t translate_klass(intptr_t k) {
+    Klass* v = TypeEntries::valid_klass(k);
+    if (v != NULL) {
+      ciKlass* klass = CURRENT_ENV->get_klass(v);
+      return with_status(klass, k);
+    }
+    return with_status(NULL, k);
+  }
+
+public:
+  static ciKlass* valid_ciklass(intptr_t k) {
+    if (!TypeEntries::is_type_none(k) &&
+        !TypeEntries::is_type_unknown(k)) {
+      return (ciKlass*)TypeEntries::klass_part(k);
+    } else {
+      return NULL;
+    }
+  }
+
+  static intptr_t with_status(ciKlass* k, intptr_t in) {
+    return TypeEntries::with_status((intptr_t)k, in);
+  }
+
+#ifndef PRODUCT
+  static void print_ciklass(outputStream* st, intptr_t k);
+#endif
+};
+
+class ciTypeStackSlotEntries : public TypeStackSlotEntries, ciTypeEntries {
+public:
+  void translate_type_data_from(const TypeStackSlotEntries* args);
+
+  ciKlass* valid_type(int i) const {
+    return valid_ciklass(type(i));
+  }
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+class ciCallTypeData : public CallTypeData {
+public:
+  ciCallTypeData(DataLayout* layout) : CallTypeData(layout) {}
+
+  ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); }
+
+  virtual void translate_from(const ProfileData* data) {
+    args()->translate_type_data_from(data->as_CallTypeData()->args());
+  }
+
+  ciKlass* valid_argument_type(int i) const {
+    return args()->valid_type(i);
+  }
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
 class ciReceiverTypeData : public ReceiverTypeData {
 public:
   ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {};
@@ -69,7 +133,7 @@
                   (intptr_t) recv);
   }
 
-  ciKlass* receiver(uint row) {
+  ciKlass* receiver(uint row) const {
     assert((uint)row < row_limit(), "oob");
     ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count);
     assert(recv == NULL || recv->is_klass(), "wrong type");
@@ -77,19 +141,19 @@
   }
 
   // Copy & translate from oop based ReceiverTypeData
-  virtual void translate_from(ProfileData* data) {
+  virtual void translate_from(const ProfileData* data) {
     translate_receiver_data_from(data);
   }
-  void translate_receiver_data_from(ProfileData* data);
+  void translate_receiver_data_from(const ProfileData* data);
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
-  void print_receiver_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
+  void print_receiver_data_on(outputStream* st) const;
 #endif
 };
 
 class ciVirtualCallData : public VirtualCallData {
   // Fake multiple inheritance...  It's a ciReceiverTypeData also.
-  ciReceiverTypeData* rtd_super() { return (ciReceiverTypeData*) this; }
+  ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
 
 public:
   ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {};
@@ -103,11 +167,44 @@
   }
 
   // Copy & translate from oop based VirtualCallData
-  virtual void translate_from(ProfileData* data) {
+  virtual void translate_from(const ProfileData* data) {
     rtd_super()->translate_receiver_data_from(data);
   }
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+class ciVirtualCallTypeData : public VirtualCallTypeData {
+private:
+  // Fake multiple inheritance...  It's a ciReceiverTypeData also.
+  ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
+
+public:
+  ciVirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(layout) {}
+
+  ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)VirtualCallTypeData::args(); }
+
+  void set_receiver(uint row, ciKlass* recv) {
+    rtd_super()->set_receiver(row, recv);
+  }
+
+  ciKlass* receiver(uint row) const {
+    return rtd_super()->receiver(row);
+  }
+
+  // Copy & translate from oop based VirtualCallData
+  virtual void translate_from(const ProfileData* data) {
+    rtd_super()->translate_receiver_data_from(data);
+    args()->translate_type_data_from(data->as_VirtualCallTypeData()->args());
+  }
+
+  ciKlass* valid_argument_type(int i) const {
+    return args()->valid_type(i);
+  }
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -247,6 +344,9 @@
   // Also set the numer of loops and blocks in the method.
   // Again, this is used to determine if a method is trivial.
   void set_compilation_stats(short loops, short blocks);
+  // If the compiler finds a profiled type that is known statically
+  // for sure, set it in the MethodData
+  void set_argument_type(int bci, int i, ciKlass* k);
 
   void load_data();
 
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -179,3 +179,16 @@
 ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) {
   GUARDED_VM_ENTRY(return make_impl(element_klass);)
 }
+
+ciKlass* ciObjArrayKlass::exact_klass() {
+  ciType* base = base_element_type();
+  if (base->is_instance_klass()) {
+    ciInstanceKlass* ik = base->as_instance_klass();
+    if (ik->exact_klass() != NULL) {
+      return this;
+    }
+  } else if (base->is_primitive_type()) {
+    return this;
+  }
+  return NULL;
+}
--- a/hotspot/src/share/vm/ci/ciObjArrayKlass.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciObjArrayKlass.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -73,6 +73,8 @@
   bool is_obj_array_klass() const { return true; }
 
   static ciObjArrayKlass* make(ciKlass* element_klass);
+
+  virtual ciKlass* exact_klass();
 };
 
 #endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP
--- a/hotspot/src/share/vm/ci/ciStreams.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciStreams.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -277,11 +277,14 @@
 class ciSignatureStream : public StackObj {
 private:
   ciSignature* _sig;
-  int    _pos;
+  int          _pos;
+  // holder is a method's holder
+  ciKlass*     _holder;
 public:
-  ciSignatureStream(ciSignature* signature) {
+  ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) {
     _sig = signature;
     _pos = 0;
+    _holder = holder;
   }
 
   bool at_return_type() { return _pos == _sig->count(); }
@@ -301,6 +304,23 @@
       return _sig->type_at(_pos);
     }
   }
+
+  // next klass in the signature
+  ciKlass* next_klass() {
+    ciKlass* sig_k;
+    if (_holder != NULL) {
+      sig_k = _holder;
+      _holder = NULL;
+    } else {
+      while (!type()->is_klass()) {
+        next();
+      }
+      assert(!at_return_type(), "passed end of signature");
+      sig_k = type()->as_klass();
+      next();
+    }
+    return sig_k;
+  }
 };
 
 
--- a/hotspot/src/share/vm/ci/ciTypeArrayKlass.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciTypeArrayKlass.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -57,6 +57,10 @@
 
   // Make an array klass corresponding to the specified primitive type.
   static ciTypeArrayKlass* make(BasicType type);
+
+  virtual ciKlass* exact_klass() {
+    return this;
+  }
 };
 
 #endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP
--- a/hotspot/src/share/vm/oops/methodData.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/oops/methodData.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -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,130 @@
 }
 
 #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(BytecodeStream* stream) {
+  int max = TypeProfileArgsLimit;
+  assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
+  Bytecode_invoke inv(stream->method(), stream->bci());
+
+  ResourceMark rm;
+  SignatureStream ss(inv.signature());
+  int args_count = MIN2(ss.reference_parameter_count(), max);
+
+  return args_count * per_arg_cell_count + (args_count > 0 ? header_cell_count() : 0);
+}
+
+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(BytecodeStream* stream) {
+  ResourceMark rm;
+
+  assert(Bytecodes::is_invoke(stream->code()), "should be invoke");
+  Bytecode_invoke inv(stream->method(), stream->bci());
+
+#ifdef ASSERT
+  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
+
+  int start = 0;
+  ArgumentOffsetComputer aos(inv.signature(), number_of_arguments()-start);
+  aos.total();
+  bool has_receiver = inv.has_receiver();
+  for (int i = start; i < number_of_arguments(); i++) {
+    set_stack_slot(i, aos.off_at(i-start) + (has_receiver ? 1 : 0));
+    set_type(i, type_none());
+  }
+}
+
+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_arguments(); i++) {
+    intptr_t p = type(i);
+    if (is_loader_alive(is_alive_cl, p)) {
+      set_type(i, type_none());
+    }
+  }
+}
+
+bool TypeStackSlotEntries::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 {
+  _pd->tab(st, true);
+  st->print("argument types");
+  for (int i = 0; i < number_of_arguments(); i++) {
+    _pd->tab(st);
+    st->print("%d: stack(%u) ", i, stack_slot(i));
+    print_klass(st, type(i));
+    st->cr();
+  }
+}
+
+void CallTypeData::print_data_on(outputStream* st) const {
+  CounterData::print_data_on(st);
+  _args.print_data_on(st);
+}
+
+void VirtualCallTypeData::print_data_on(outputStream* st) const {
+  VirtualCallData::print_data_on(st);
+  _args.print_data_on(st);
+}
+#endif
+
 // ==================================================================
 // ReceiverTypeData
 //
@@ -169,7 +292,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 +313,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);
 }
@@ -246,7 +369,7 @@
 
 
 #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;
@@ -281,7 +404,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());
@@ -355,7 +478,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());
@@ -369,7 +492,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++) {
@@ -407,7 +530,11 @@
     }
   case Bytecodes::_invokespecial:
   case Bytecodes::_invokestatic:
-    return CounterData::static_cell_count();
+    if (MethodData::profile_arguments()) {
+      return variable_cell_count;
+    } else {
+      return CounterData::static_cell_count();
+    }
   case Bytecodes::_goto:
   case Bytecodes::_goto_w:
   case Bytecodes::_jsr:
@@ -415,9 +542,17 @@
     return JumpData::static_cell_count();
   case Bytecodes::_invokevirtual:
   case Bytecodes::_invokeinterface:
-    return VirtualCallData::static_cell_count();
+    if (MethodData::profile_arguments()) {
+      return variable_cell_count;
+    } else {
+      return VirtualCallData::static_cell_count();
+    }
   case Bytecodes::_invokedynamic:
-    return CounterData::static_cell_count();
+    if (MethodData::profile_arguments()) {
+      return variable_cell_count;
+    } else {
+      return CounterData::static_cell_count();
+    }
   case Bytecodes::_ret:
     return RetData::static_cell_count();
   case Bytecodes::_ifeq:
@@ -453,7 +588,34 @@
     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(), "should be collecting args profile");
+      if (profile_arguments_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(), "should be collecting args profile");
+      if (profile_arguments_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.
@@ -499,6 +661,7 @@
   // 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);
+
   return object_size;
 }
 
@@ -534,10 +697,20 @@
     }
     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())) {
+      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:
@@ -546,15 +719,35 @@
     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())) {
+      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())) {
+      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;
@@ -585,6 +778,11 @@
     break;
   }
   assert(tag == DataLayout::multi_branch_data_tag ||
+         (MethodData::profile_arguments() &&
+          (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");
@@ -631,6 +829,10 @@
     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);
   };
 }
 
@@ -898,3 +1100,42 @@
   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;
+}
+
+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);
+}
+
--- a/hotspot/src/share/vm/oops/methodData.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/oops/methodData.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -117,7 +117,9 @@
     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
   };
 
   enum {
@@ -165,7 +167,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);
   }
 
@@ -175,11 +177,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;
   }
 
@@ -198,7 +200,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];
   }
 
@@ -206,7 +208,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;
   }
@@ -254,19 +256,22 @@
 class     CounterData;
 class       ReceiverTypeData;
 class         VirtualCallData;
+class           VirtualCallTypeData;
 class       RetData;
+class       CallTypeData;
 class   JumpData;
 class     BranchData;
 class   ArrayData;
 class     MultiBranchData;
 class     ArgInfoData;
 
-
 // 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 TypeStackSlotEntries;
 private:
 #ifndef PRODUCT
   enum {
@@ -280,6 +285,7 @@
 
 protected:
   DataLayout* data() { return _data; }
+  const DataLayout* data() const { return _data; }
 
   enum {
     cell_size = DataLayout::cell_size
@@ -287,7 +293,7 @@
 
 public:
   // How many cells are in this?
-  virtual int cell_count() {
+  virtual int cell_count() const {
     ShouldNotReachHere();
     return -1;
   }
@@ -307,7 +313,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);
   }
@@ -317,7 +323,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) {
@@ -326,23 +332,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, cast_from_oop<intptr_t>(value));
   }
-  oop oop_at(int 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);
   }
 
@@ -362,7 +368,7 @@
   // Constructor for invalid ProfileData.
   ProfileData();
 
-  u2 bci() {
+  u2 bci() const {
     return data()->bci();
   }
 
@@ -370,7 +376,7 @@
     return (address)_data;
   }
 
-  int trap_state() {
+  int trap_state() const {
     return data()->trap_state();
   }
   void set_trap_state(int new_state) {
@@ -378,58 +384,68 @@
   }
 
   // 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; }
 
 
-  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;
+  }
 
 
   // Subclass specific initialization
@@ -443,15 +459,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
 };
 
@@ -470,13 +486,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();
   }
 
@@ -498,7 +514,7 @@
   }
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -514,18 +530,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);
   }
 
@@ -542,7 +558,7 @@
   }
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -570,18 +586,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);
   }
 
@@ -598,7 +614,7 @@
     return cnt;
   }
 
-  int displacement() {
+  int displacement() const {
     return int_at(displacement_off_set);
   }
 
@@ -615,7 +631,332 @@
   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
+  };
+
+  // Start with a header if needed. It stores the number of cells used
+  // for this call type information. Unless we collect only profiling
+  // for a single argument the number of cells is unknown statically.
+  static int header_cell_count() {
+    return (TypeProfileArgsLimit > 1) ? 1 : 0;
+  }
+
+  static int cell_count_local_offset() {
+     assert(arguments_profiling_enabled() && TypeProfileArgsLimit > 1, "no cell count");
+     return 0;
+   }
+
+  int cell_count_global_offset() const {
+    return _base_off + cell_count_local_offset();
+  }
+
+  // offset of cell for stack slot for entry i within ProfileData object
+  int stack_slot_global_offset(int i) const {
+    return _base_off + stack_slot_local_offset(i);
+  }
+
+  void check_number_of_arguments(int total) {
+    assert(number_of_arguments() == total, "should be set in DataLayout::initialize");
+  }
+
+  // number of cells not counting the header
+  int cell_count_no_header() const {
+    return _pd->uint_at(cell_count_global_offset());
+  }
+
+  static bool arguments_profiling_enabled();
+  static void assert_arguments_profiling_enabled() {
+    assert(arguments_profiling_enabled(), "args profiling should be on");
+  }
+
+protected:
+
+  // offset of cell for type for entry i within ProfileData object
+  int type_global_offset(int i) const {
+    return _base_off + type_local_offset(i);
+  }
+
+public:
+
+  TypeStackSlotEntries(int base_off)
+    : TypeEntries(base_off) {}
+
+  static int compute_cell_count(BytecodeStream* stream);
+
+  static void initialize(DataLayout* dl, int base, int cell_count) {
+    if (TypeProfileArgsLimit > 1) {
+      int off = base + cell_count_local_offset();
+      dl->set_cell_at(off, cell_count - base - header_cell_count());
+    }
+  }
+
+  void post_initialize(BytecodeStream* stream);
+
+  int number_of_arguments() const {
+    assert_arguments_profiling_enabled();
+    if (TypeProfileArgsLimit > 1) {
+      int cell_count = cell_count_no_header();
+      int nb = cell_count / TypeStackSlotEntries::per_arg_count();
+      assert(nb > 0 && nb <= TypeProfileArgsLimit , "only when we profile args");
+      return nb;
+    } else {
+      assert(TypeProfileArgsLimit == 1, "at least one arg");
+      return 1;
+    }
+  }
+
+  int cell_count() const {
+    assert_arguments_profiling_enabled();
+    if (TypeProfileArgsLimit > 1) {
+      return _base_off + header_cell_count() + _pd->int_at_unchecked(cell_count_global_offset());
+    } else {
+      return _base_off + TypeStackSlotEntries::per_arg_count();
+    }
+  }
+
+  // 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) {
+    assert_arguments_profiling_enabled();
+    return header_cell_count() + 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 header_cell_count() + i * per_arg_cell_count + type_entry;
+  }
+
+  // stack slot for entry i
+  uint stack_slot(int i) const {
+    assert(i >= 0 && i < number_of_arguments(), "oob");
+    return _pd->uint_at(stack_slot_global_offset(i));
+  }
+
+  // set stack slot for entry i
+  void set_stack_slot(int i, uint num) {
+    assert(i >= 0 && i < number_of_arguments(), "oob");
+    _pd->set_uint_at(stack_slot_global_offset(i), num);
+  }
+
+  // type for entry i
+  intptr_t type(int i) const {
+    assert(i >= 0 && i < number_of_arguments(), "oob");
+    return _pd->intptr_at(type_global_offset(i));
+  }
+
+  // set type for entry i
+  void set_type(int i, intptr_t k) {
+    assert(i >= 0 && i < number_of_arguments(), "oob");
+    _pd->set_intptr_at(type_global_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 ;
+  }
+
+  // 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 type_offset(int i) {
+     return in_ByteSize(type_local_offset(i) * DataLayout::cell_size);
+   }
+
+  // GC support
+  void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
+
+#ifndef PRODUCT
+  void print_data_on(outputStream* st) const;
+#endif
+};
+
+// CallTypeData
+//
+// A CallTypeData is used to access profiling information about a non
+// virtual call for which we collect type information about arguments.
+class CallTypeData : public CounterData {
+private:
+  TypeStackSlotEntries _args;
+
+public:
+  CallTypeData(DataLayout* layout) :
+    CounterData(layout), _args(CounterData::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);
+  }
+
+  const TypeStackSlotEntries* args() const { return &_args; }
+
+  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() + TypeStackSlotEntries::compute_cell_count(stream);
+  }
+
+  static void initialize(DataLayout* dl, int cell_count) {
+    TypeStackSlotEntries::initialize(dl, CounterData::static_cell_count(), cell_count);
+  }
+
+  virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
+    _args.post_initialize(stream);
+  }
+
+  virtual int cell_count() const {
+    return _args.cell_count();
+  }
+
+  uint number_of_arguments() const {
+    return args()->number_of_arguments();
+  }
+
+  void set_argument_type(int i, Klass* k) {
+    intptr_t current = _args.type(i);
+    _args.set_type(i, TypeEntries::with_status(k, current));
+  }
+
+  // Code generation support
+  static ByteSize args_data_offset() {
+    return cell_offset(CounterData::static_cell_count()) + TypeStackSlotEntries::args_data_offset();
+  }
+
+  // GC support
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
+    _args.clean_weak_klass_links(is_alive_closure);
+  }
+
+#ifndef PRODUCT
+  virtual void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -636,16 +977,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();
   }
 
@@ -660,7 +1002,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));
@@ -673,7 +1015,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));
   }
@@ -721,8 +1063,8 @@
   virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
 
 #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
 };
 
@@ -733,10 +1075,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.
@@ -744,7 +1087,7 @@
     return ReceiverTypeData::static_cell_count();
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -754,7 +1097,73 @@
   }
 
 #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.
+class VirtualCallTypeData : public VirtualCallData {
+private:
+  TypeStackSlotEntries _args;
+
+public:
+  VirtualCallTypeData(DataLayout* layout) :
+    VirtualCallData(layout), _args(VirtualCallData::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);
+  }
+
+  const TypeStackSlotEntries* args() const { return &_args; }
+
+  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() + TypeStackSlotEntries::compute_cell_count(stream);
+  }
+
+  static void initialize(DataLayout* dl, int cell_count) {
+    TypeStackSlotEntries::initialize(dl, VirtualCallData::static_cell_count(), cell_count);
+  }
+
+  virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {
+    _args.post_initialize(stream);
+  }
+
+  virtual int cell_count() const {
+    return _args.cell_count();
+  }
+
+  uint number_of_arguments() const {
+    return args()->number_of_arguments();
+  }
+
+  void set_argument_type(int i, Klass* k) {
+    intptr_t current = _args.type(i);
+    _args.set_type(i, TypeEntries::with_status(k, current));
+  }
+
+  // Code generation support
+  static ByteSize args_data_offset() {
+    return cell_offset(VirtualCallData::static_cell_count()) + TypeStackSlotEntries::args_data_offset();
+  }
+
+  // GC support
+  virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
+    ReceiverTypeData::clean_weak_klass_links(is_alive_closure);
+    _args.clean_weak_klass_links(is_alive_closure);
+  }
+
+#ifndef PRODUCT
+  virtual void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -797,7 +1206,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.
@@ -807,7 +1216,7 @@
     return counter_cell_count + (uint) BciProfileWidth * ret_row_cell_count;
   }
 
-  virtual int cell_count() {
+  virtual int cell_count() const {
     return static_cell_count();
   }
 
@@ -825,13 +1234,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));
   }
 
@@ -853,7 +1262,7 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -878,18 +1287,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);
   }
 
@@ -917,7 +1326,7 @@
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -935,15 +1344,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);
   }
@@ -960,17 +1369,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;
   }
 
@@ -1017,29 +1426,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);
@@ -1074,7 +1483,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,14 +1494,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);
   }
 
@@ -1101,7 +1510,7 @@
   }
 
 #ifndef PRODUCT
-  void print_data_on(outputStream* st);
+  void print_data_on(outputStream* st) const;
 #endif
 };
 
@@ -1271,6 +1680,18 @@
   // 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);
+
 public:
   static int header_size() {
     return sizeof(MethodData)/wordSize;
@@ -1510,6 +1931,8 @@
   // verification
   void verify_on(outputStream* st);
   void verify_data_on(outputStream* st);
+
+  static bool profile_arguments();
 };
 
 #endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -2648,6 +2648,13 @@
   product(bool, AggressiveOpts, false,                                      \
           "Enable aggressive optimizations - see arguments.cpp")            \
                                                                             \
+  product_pd(uintx, TypeProfileLevel,                                       \
+          "Type profiling of arguments at call:"                            \
+          "0->off ; 1->js292 only; 2->all methods")                         \
+                                                                            \
+  product(intx, TypeProfileArgsLimit,     2,                                \
+          "max number of call arguments to consider for type profiling")    \
+                                                                            \
   /* statistics */                                                          \
   develop(bool, CountCompiledCalls, false,                                  \
           "counts method invocations")                                      \
@@ -3760,7 +3767,6 @@
   product(bool, UseLockedTracing, false,                                    \
           "Use locked-tracing when doing event-based tracing")
 
-
 /*
  *  Macros for factoring of globals
  */
--- a/hotspot/src/share/vm/runtime/java.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/runtime/java.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -183,6 +183,7 @@
   collected_profiled_methods->sort(&compare_methods);
 
   int count = collected_profiled_methods->length();
+  int total_size = 0;
   if (count > 0) {
     for (int index = 0; index < count; index++) {
       Method* m = collected_profiled_methods->at(index);
@@ -190,10 +191,13 @@
       tty->print_cr("------------------------------------------------------------------------");
       //m->print_name(tty);
       m->print_invocation_count();
+      tty->print_cr("  mdo size: %d bytes", m->method_data()->size_in_bytes());
       tty->cr();
       m->print_codes();
+      total_size += m->method_data()->size_in_bytes();
     }
     tty->print_cr("------------------------------------------------------------------------");
+    tty->print_cr("Total MDO size: %d bytes", total_size);
   }
 }
 
--- a/hotspot/src/share/vm/runtime/signature.cpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/runtime/signature.cpp	Wed Oct 09 16:32:21 2013 +0200
@@ -378,6 +378,16 @@
   return result;
 }
 
+int SignatureStream::reference_parameter_count() {
+  int args_count = 0;
+  for ( ; !at_return_type(); next()) {
+    if (is_object()) {
+      args_count++;
+    }
+  }
+  return args_count;
+}
+
 bool SignatureVerifier::is_valid_signature(Symbol* sig) {
   const char* signature = (const char*)sig->bytes();
   ssize_t len = sig->utf8_length();
--- a/hotspot/src/share/vm/runtime/signature.hpp	Wed Oct 09 11:05:17 2013 -0700
+++ b/hotspot/src/share/vm/runtime/signature.hpp	Wed Oct 09 16:32:21 2013 +0200
@@ -401,6 +401,9 @@
 
   // return same as_symbol except allocation of new symbols is avoided.
   Symbol* as_symbol_or_null();
+
+  // count the number of references in the signature
+  int reference_parameter_count();
 };
 
 class SignatureVerifier : public StackObj {