view ppc_patches/0201_C_interpreter-implement_bytecode_profiling.patch @ 4881:edf2bb42e70f

Recent changes to patch queue
author goetz
date Fri, 28 Jun 2013 16:31:09 +0200
parents df79d76c17ab
children 874e94d3b21d
line wrap: on
line source
# HG changeset patch
# Parent 738d32552a9693f1f440426756e7b4906b3b7552
C-interpreter: implement bytecode profiling.

diff -r 738d32552a96 src/share/vm/interpreter/bytecodeInterpreter.cpp
--- a/src/share/vm/interpreter/bytecodeInterpreter.cpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp	Fri Jun 28 14:34:21 2013 +0200
@@ -28,6 +28,7 @@
 #include "interpreter/bytecodeHistogram.hpp"
 #include "interpreter/bytecodeInterpreter.hpp"
 #include "interpreter/bytecodeInterpreter.inline.hpp"
+#include "interpreter/bytecodeInterpreterProfiling.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "memory/cardTableModRefBS.hpp"
@@ -143,10 +144,11 @@
  * is no entry point to do the transition to vm so we just
  * do it by hand here.
  */
-#define VM_JAVA_ERROR_NO_JUMP(name, msg)                                          \
+#define VM_JAVA_ERROR_NO_JUMP(name, msg, note_a_trap)                             \
     DECACHE_STATE();                                                              \
     SET_LAST_JAVA_FRAME();                                                        \
     {                                                                             \
+       InterpreterRuntime::note_a_trap(THREAD, istate->method(), BCI());          \
        ThreadInVMfromJava trans(THREAD);                                          \
        Exceptions::_throw_msg(THREAD, __FILE__, __LINE__, name, msg);             \
     }                                                                             \
@@ -154,8 +156,8 @@
     CACHE_STATE();
 
 // Normal throw of a java error
-#define VM_JAVA_ERROR(name, msg)                                                  \
-    VM_JAVA_ERROR_NO_JUMP(name, msg)                                              \
+#define VM_JAVA_ERROR(name, msg, note_a_trap)                                     \
+    VM_JAVA_ERROR_NO_JUMP(name, msg, note_a_trap)                                 \
     goto handle_exception;
 
 #ifdef PRODUCT
@@ -341,7 +343,23 @@
       if (UseLoopCounter) {                                                                         \
         bool do_OSR = UseOnStackReplacement;                                                        \
         mcs->backedge_counter()->increment();                                                       \
-        if (do_OSR) do_OSR = mcs->backedge_counter()->reached_InvocationLimit();                    \
+        if (ProfileInterpreter) {                                                                   \
+          BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);                                   \
+          /* Check for overflow against MDO count. */                                               \
+          do_OSR = do_OSR                                                                           \
+            && (mdo_last_branch_taken_count >= (uint)InvocationCounter::InterpreterBackwardBranchLimit)\
+            /* When ProfileInterpreter is on, the backedge_count comes     */                       \
+            /* from the methodDataOop, which value does not get reset on   */                       \
+            /* the call to frequency_counter_overflow().  To avoid         */                       \
+            /* excessive calls to the overflow routine while the method is */                       \
+            /* being compiled, add a second test to make sure the overflow */                       \
+            /* function is called only once every overflow_frequency.      */                       \
+            && (!(mdo_last_branch_taken_count & 1023));                                             \
+        } else {                                                                                    \
+          /* check for overflow of backedge counter */                                              \
+          do_OSR = do_OSR                                                                           \
+            && mcs->invocation_counter()->reached_InvocationLimit(mcs->backedge_counter());         \
+        }                                                                                           \
         if (do_OSR) {                                                                               \
           nmethod*  osr_nmethod;                                                                    \
           OSR_REQUEST(osr_nmethod, branch_pc);                                                      \
@@ -354,7 +372,6 @@
           }                                                                                         \
         }                                                                                           \
       }  /* UseCompiler ... */                                                                      \
-      mcs->invocation_counter()->increment();                                                       \
       SAFEPOINT;                                                                                    \
     }
 
@@ -387,16 +404,20 @@
 #undef CACHE_FRAME
 #define CACHE_FRAME()
 
+// BCI() returns the current bytecode-index.
+#undef  BCI
+#define BCI()           ((int)(intptr_t)(pc - (intptr_t)istate->method()->code_base()))
+
 /*
  * CHECK_NULL - Macro for throwing a NullPointerException if the object
  * passed is a null ref.
  * On some architectures/platforms it should be possible to do this implicitly
  */
 #undef CHECK_NULL
-#define CHECK_NULL(obj_)                                                 \
-    if ((obj_) == NULL) {                                                \
-        VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), "");  \
-    }                                                                    \
+#define CHECK_NULL(obj_)                                                                      \
+    if ((obj_) == NULL) {                                                                     \
+      VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), "", note_nullCheck_trap);  \
+    }                                                                                         \
     VERIFY_OOP(obj_)
 
 #define VMdoubleConstZero() 0.0
@@ -630,6 +651,13 @@
          topOfStack < istate->stack_base(),
          "Stack top out of range");
 
+#ifdef CC_INTERP_PROFILE
+  // MethodData's last branch taken count.
+  uint mdo_last_branch_taken_count = 0;
+#else
+  const uint mdo_last_branch_taken_count = 0;
+#endif
+
   switch (istate->msg()) {
     case initialize: {
       if (initialized++) ShouldNotReachHere(); // Only one initialize call
@@ -651,15 +679,12 @@
           METHOD->increment_interpreter_invocation_count(THREAD);
         }
         mcs->invocation_counter()->increment();
-        if (mcs->invocation_counter()->reached_InvocationLimit()) {
-            CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception);
-
-            // We no longer retry on a counter overflow
-
-            // istate->set_msg(retry_method);
-            // THREAD->clr_do_not_unlock();
-            // return;
+        if (mcs->invocation_counter()->reached_InvocationLimit(mcs->backedge_counter())) {
+          CALL_VM((void)InterpreterRuntime::frequency_counter_overflow(THREAD, NULL), handle_exception);
+          // We no longer retry on a counter overflow
         }
+        // Get or create profile data. Check for pending (async) exceptions.
+        BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);
         SAFEPOINT;
       }
 
@@ -681,7 +706,6 @@
       }
 #endif // HACK
 
-
       // lock method if synchronized
       if (METHOD->is_synchronized()) {
         // oop rcvr = locals[0].j.r;
@@ -796,9 +820,18 @@
     case popping_frame: {
       // returned from a java call to pop the frame, restart the call
       // clear the message so we don't confuse ourselves later
-      ShouldNotReachHere();  // we don't return this.
+      // Commented out ShouldNotReachHere() below, because we do reach
+      // here when the frame manager calls the interpreter loop after
+      // popping the top frame.
+      // ShouldNotReachHere();  // we don't return this.
       assert(THREAD->pop_frame_in_process(), "wrong frame pop state");
       istate->set_msg(no_request);
+      if (_compiling) {
+        // Set MDX back to the ProfileData of the invoke bytecode that will be
+        // restarted.
+        SET_MDX(NULL);
+        BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);
+      }
       THREAD->clr_pop_frame_in_process();
       goto run;
     }
@@ -832,6 +865,11 @@
       if (THREAD->has_pending_exception()) goto handle_exception;
       // Update the pc by the saved amount of the invoke bytecode size
       UPDATE_PC(istate->bcp_advance());
+
+      if (_compiling) {
+        // Get or create profile data. Check for pending (async) exceptions.
+        BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);
+      }
       goto run;
     }
 
@@ -839,6 +877,11 @@
       // Returned from an opcode that will reexecute. Deopt was
       // a result of a PopFrame request.
       //
+
+      if (_compiling) {
+        // Get or create profile data. Check for pending (async) exceptions.
+        BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);
+      }
       goto run;
     }
 
@@ -861,6 +904,11 @@
       }
       UPDATE_PC(Bytecodes::length_at(METHOD, pc));
       if (THREAD->has_pending_exception()) goto handle_exception;
+
+      if (_compiling) {
+        // Get or create profile data. Check for pending (async) exceptions.
+        BI_PROFILE_GET_OR_CREATE_METHOD_DATA(handle_exception);
+      }
       goto run;
     }
     case got_monitors: {
@@ -1111,6 +1159,11 @@
           uint16_t reg = Bytes::get_Java_u2(pc + 2);
 
           opcode = pc[1];
+
+          // Wide and it's sub-bytecode are counted as separate instructions. If we
+          // don't account for this here, the bytecode trace skips the next bytecode.
+          DO_UPDATE_INSTRUCTION_COUNT(opcode);
+
           switch(opcode) {
               case Bytecodes::_aload:
                   VERIFY_OOP(LOCALS_OBJECT(reg));
@@ -1154,10 +1207,13 @@
                   UPDATE_PC_AND_CONTINUE(6);
               }
               case Bytecodes::_ret:
+                  // Profile ret.
+                  BI_PROFILE_UPDATE_RET(/*bci=*/((int)(intptr_t)(LOCALS_ADDR(reg))));
+                  // Now, update the pc.
                   pc = istate->method()->code_base() + (intptr_t)(LOCALS_ADDR(reg));
                   UPDATE_PC_AND_CONTINUE(0);
               default:
-                  VM_JAVA_ERROR(vmSymbols::java_lang_InternalError(), "undefined opcode");
+                  VM_JAVA_ERROR(vmSymbols::java_lang_InternalError(), "undefined opcode", note_no_trap);
           }
       }
 
@@ -1238,7 +1294,7 @@
       CASE(_i##opcname):                                                \
           if (test && (STACK_INT(-1) == 0)) {                           \
               VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
-                            "/ by zero");                               \
+                            "/ by zero", note_div0Check_trap);          \
           }                                                             \
           SET_STACK_INT(VMint##opname(STACK_INT(-2),                    \
                                       STACK_INT(-1)),                   \
@@ -1250,7 +1306,7 @@
             jlong l1 = STACK_LONG(-1);                                  \
             if (VMlongEqz(l1)) {                                        \
               VM_JAVA_ERROR(vmSymbols::java_lang_ArithmeticException(), \
-                            "/ by long zero");                          \
+                            "/ by long zero", note_div0Check_trap);     \
             }                                                           \
           }                                                             \
           /* First long at (-1,-2) next long at (-3,-4) */              \
@@ -1463,17 +1519,23 @@
 
 #define COMPARISON_OP(name, comparison)                                      \
       CASE(_if_icmp##name): {                                                \
-          int skip = (STACK_INT(-2) comparison STACK_INT(-1))                \
+          const bool cmp = (STACK_INT(-2) comparison STACK_INT(-1));         \
+          int skip = cmp                                                     \
                       ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
           address branch_pc = pc;                                            \
+          /* Profile branch. */                                              \
+          BI_PROFILE_UPDATE_BRANCH(/*is_taken=*/cmp);                        \
           UPDATE_PC_AND_TOS(skip, -2);                                       \
           DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
           CONTINUE;                                                          \
       }                                                                      \
       CASE(_if##name): {                                                     \
-          int skip = (STACK_INT(-1) comparison 0)                            \
+          const bool cmp = (STACK_INT(-1) comparison 0);                     \
+          int skip = cmp                                                     \
                       ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
           address branch_pc = pc;                                            \
+          /* Profile branch. */                                              \
+          BI_PROFILE_UPDATE_BRANCH(/*is_taken=*/cmp);                        \
           UPDATE_PC_AND_TOS(skip, -1);                                       \
           DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
           CONTINUE;                                                          \
@@ -1482,9 +1544,12 @@
 #define COMPARISON_OP2(name, comparison)                                     \
       COMPARISON_OP(name, comparison)                                        \
       CASE(_if_acmp##name): {                                                \
-          int skip = (STACK_OBJECT(-2) comparison STACK_OBJECT(-1))          \
+          const bool cmp = (STACK_OBJECT(-2) comparison STACK_OBJECT(-1));   \
+          int skip = cmp                                                     \
                        ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;            \
           address branch_pc = pc;                                            \
+          /* Profile branch. */                                              \
+          BI_PROFILE_UPDATE_BRANCH(/*is_taken=*/cmp);                        \
           UPDATE_PC_AND_TOS(skip, -2);                                       \
           DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
           CONTINUE;                                                          \
@@ -1492,9 +1557,12 @@
 
 #define NULL_COMPARISON_NOT_OP(name)                                         \
       CASE(_if##name): {                                                     \
-          int skip = (!(STACK_OBJECT(-1) == NULL))                           \
+          const bool cmp = (!(STACK_OBJECT(-1) == NULL));                    \
+          int skip = cmp                                                     \
                       ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
           address branch_pc = pc;                                            \
+          /* Profile branch. */                                              \
+          BI_PROFILE_UPDATE_BRANCH(/*is_taken=*/cmp);                        \
           UPDATE_PC_AND_TOS(skip, -1);                                       \
           DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
           CONTINUE;                                                          \
@@ -1502,9 +1570,12 @@
 
 #define NULL_COMPARISON_OP(name)                                             \
       CASE(_if##name): {                                                     \
-          int skip = ((STACK_OBJECT(-1) == NULL))                            \
+          const bool cmp = ((STACK_OBJECT(-1) == NULL));                     \
+          int skip = cmp                                                     \
                       ? (int16_t)Bytes::get_Java_u2(pc + 1) : 3;             \
           address branch_pc = pc;                                            \
+          /* Profile branch. */                                              \
+          BI_PROFILE_UPDATE_BRANCH(/*is_taken=*/cmp);                        \
           UPDATE_PC_AND_TOS(skip, -1);                                       \
           DO_BACKEDGE_CHECKS(skip, branch_pc);                               \
           CONTINUE;                                                          \
@@ -1527,9 +1598,14 @@
           int32_t  high = Bytes::get_Java_u4((address)&lpc[2]);
           int32_t  skip;
           key -= low;
-          skip = ((uint32_t) key > (uint32_t)(high - low))
-                      ? Bytes::get_Java_u4((address)&lpc[0])
-                      : Bytes::get_Java_u4((address)&lpc[key + 3]);
+          if (((uint32_t) key > (uint32_t)(high - low))) {
+            key = -1;
+            skip = Bytes::get_Java_u4((address)&lpc[0]);
+          } else {
+            skip = Bytes::get_Java_u4((address)&lpc[key + 3]);
+          }
+          // Profile switch.
+          BI_PROFILE_UPDATE_SWITCH(/*switch_index=*/key);
           // Does this really need a full backedge check (osr?)
           address branch_pc = pc;
           UPDATE_PC_AND_TOS(skip, -1);
@@ -1543,14 +1619,21 @@
           jint* lpc  = (jint*)VMalignWordUp(pc+1);
           int32_t  key  = STACK_INT(-1);
           int32_t  skip = Bytes::get_Java_u4((address) lpc); /* default amount */
+          // Remember index.
+          int      index = -1;
+          int      newindex = 0;
           int32_t  npairs = Bytes::get_Java_u4((address) &lpc[1]);
           while (--npairs >= 0) {
-              lpc += 2;
-              if (key == (int32_t)Bytes::get_Java_u4((address)lpc)) {
-                  skip = Bytes::get_Java_u4((address)&lpc[1]);
-                  break;
-              }
+            lpc += 2;
+            if (key == (int32_t)Bytes::get_Java_u4((address)lpc)) {
+              skip = Bytes::get_Java_u4((address)&lpc[1]);
+              index = newindex;
+              break;
+            }
+            newindex += 1;
           }
+          // Profile switch.
+          BI_PROFILE_UPDATE_SWITCH(/*switch_index=*/index);
           address branch_pc = pc;
           UPDATE_PC_AND_TOS(skip, -1);
           DO_BACKEDGE_CHECKS(skip, branch_pc);
@@ -1635,7 +1718,7 @@
       if ((uint32_t)index >= (uint32_t)arrObj->length()) {                     \
           sprintf(message, "%d", index);                                       \
           VM_JAVA_ERROR(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), \
-                        message);                                              \
+                        message, note_rangeCheck_trap);                        \
       }
 
       /* 32-bit loads. These handle conversion from < 32-bit types */
@@ -1716,15 +1799,22 @@
           // arrObj, index are set
           if (rhsObject != NULL) {
             /* Check assignability of rhsObject into arrObj */
-            Klass* rhsKlassOop = rhsObject->klass(); // EBX (subclass)
-            Klass* elemKlassOop = ObjArrayKlass::cast(arrObj->klass())->element_klass(); // superklass EAX
+            Klass* rhsKlass = rhsObject->klass(); // EBX (subclass)
+            Klass* elemKlass = ObjArrayKlass::cast(arrObj->klass())->element_klass(); // superklass EAX
             //
             // Check for compatibilty. This check must not GC!!
             // Seems way more expensive now that we must dispatch
             //
-            if (rhsKlassOop != elemKlassOop && !rhsKlassOop->is_subtype_of(elemKlassOop)) { // ebx->is...
-              VM_JAVA_ERROR(vmSymbols::java_lang_ArrayStoreException(), "");
+            if (rhsKlass != elemKlass && !rhsKlass->is_subtype_of(elemKlass)) { // ebx->is...
+              // Decrement counter if subtype check failed.
+              BI_PROFILE_SUBTYPECHECK_FAILED(rhsKlass);
+              VM_JAVA_ERROR(vmSymbols::java_lang_ArrayStoreException(), "", note_arrayCheck_trap);
             }
+            // Profile checkcast with null_seen and receiver.
+            BI_PROFILE_UPDATE_CHECKCAST(/*null_seen=*/false, rhsKlass);
+          } else {
+            // Profile checkcast with null_seen and receiver.
+            BI_PROFILE_UPDATE_CHECKCAST(/*null_seen=*/true, NULL);
           }
           // G1GC port. Use accessor instead of storing manually.
           // Takes care of write barriers internally and replaces the code above.
@@ -2124,10 +2214,14 @@
             if (UseTLAB) {
               result = (oop) THREAD->tlab().allocate(obj_size);
             }
+            // Disable non-TLAB-based fast-path, because profiling requires that all
+            // allocations go through InterpreterRuntime::_new() if THREAD->tlab().allocate
+            // returns NULL.
+#ifndef CC_INTERP_PROFILE
             if (result == NULL) {
               need_zero = true;
               // Try allocate in shared eden
-        retry:
+            retry:
               HeapWord* compare_to = *Universe::heap()->top_addr();
               HeapWord* new_top = compare_to + obj_size;
               if (new_top <= *Universe::heap()->end_addr()) {
@@ -2137,6 +2231,7 @@
                 result = (oop) compare_to;
               }
             }
+#endif
             if (result != NULL) {
               // Initialize object (if nonzero size and need) and then the header
               if (need_zero ) {
@@ -2192,42 +2287,40 @@
           if (STACK_OBJECT(-1) != NULL) {
             VERIFY_OOP(STACK_OBJECT(-1));
             u2 index = Bytes::get_Java_u2(pc+1);
-            if (ProfileInterpreter) {
-              // needs Profile_checkcast QQQ
-              ShouldNotReachHere();
-            }
             // Constant pool may have actual klass or unresolved klass. If it is
             // unresolved we must resolve it
             if (METHOD->constants()->tag_at(index).is_unresolved_klass()) {
               CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
             }
             Klass* klassOf = (Klass*) METHOD->constants()->slot_at(index).get_klass();
-            Klass* objKlassOop = STACK_OBJECT(-1)->klass(); //ebx
+            Klass* objKlass = STACK_OBJECT(-1)->klass(); //ebx
             //
             // Check for compatibilty. This check must not GC!!
             // Seems way more expensive now that we must dispatch
             //
-            if (objKlassOop != klassOf &&
-                !objKlassOop->is_subtype_of(klassOf)) {
+            if (objKlass != klassOf && !objKlass->is_subtype_of(klassOf)) {
+              // Decrement counter at checkcast.
+              BI_PROFILE_SUBTYPECHECK_FAILED(objKlass);
               ResourceMark rm(THREAD);
-              const char* objName = objKlassOop->external_name();
+              const char* objName = objKlass->external_name();
               const char* klassName = klassOf->external_name();
               char* message = SharedRuntime::generate_class_cast_message(
                 objName, klassName);
-              VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message);
+              VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message, note_classCheck_trap);
             }
+            // Profile checkcast with null_seen and receiver.
+            BI_PROFILE_UPDATE_CHECKCAST(/*null_seen=*/false, objKlass);
           } else {
-            if (UncommonNullCast) {
-//              istate->method()->set_null_cast_seen();
-// [RGV] Not sure what to do here!
-
-            }
+            // Profile checkcast with null_seen and receiver.
+            BI_PROFILE_UPDATE_CHECKCAST(/*null_seen=*/true, NULL);
           }
           UPDATE_PC_AND_CONTINUE(3);
 
       CASE(_instanceof):
           if (STACK_OBJECT(-1) == NULL) {
             SET_STACK_INT(0, -1);
+            // Profile instanceof with null_seen and receiver.
+            BI_PROFILE_UPDATE_INSTANCEOF(/*null_seen=*/true, NULL);
           } else {
             VERIFY_OOP(STACK_OBJECT(-1));
             u2 index = Bytes::get_Java_u2(pc+1);
@@ -2237,16 +2330,20 @@
               CALL_VM(InterpreterRuntime::quicken_io_cc(THREAD), handle_exception);
             }
             Klass* klassOf = (Klass*) METHOD->constants()->slot_at(index).get_klass();
-            Klass* objKlassOop = STACK_OBJECT(-1)->klass();
+            Klass* objKlass = STACK_OBJECT(-1)->klass();
             //
             // Check for compatibilty. This check must not GC!!
             // Seems way more expensive now that we must dispatch
             //
-            if ( objKlassOop == klassOf || objKlassOop->is_subtype_of(klassOf)) {
+            if ( objKlass == klassOf || objKlass->is_subtype_of(klassOf)) {
               SET_STACK_INT(1, -1);
             } else {
               SET_STACK_INT(0, -1);
+              // Decrement counter at checkcast.
+              BI_PROFILE_SUBTYPECHECK_FAILED(objKlass);
             }
+            // Profile instanceof with null_seen and receiver.
+            BI_PROFILE_UPDATE_INSTANCEOF(/*null_seen=*/false, objKlass);
           }
           UPDATE_PC_AND_CONTINUE(3);
 
@@ -2389,6 +2486,9 @@
         istate->set_callee_entry_point(method->from_interpreted_entry());
         istate->set_bcp_advance(5);
 
+        // Invokedynamic has got a call counter, just like an invokestatic -> increment!
+        BI_PROFILE_UPDATE_CALL();
+
         UPDATE_PC_AND_RETURN(0); // I'll be back...
       }
 
@@ -2421,6 +2521,9 @@
         istate->set_callee_entry_point(method->from_interpreted_entry());
         istate->set_bcp_advance(3);
 
+        // Invokehandle has got a call counter, just like a final call -> increment!
+        BI_PROFILE_UPDATE_FINALCALL();
+
         UPDATE_PC_AND_RETURN(0); // I'll be back...
       }
 
@@ -2448,14 +2551,18 @@
           CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
           if (cache->is_vfinal()) {
             callee = cache->f2_as_vfinal_method();
+            // Profile 'special case of invokeinterface' final call.
+            BI_PROFILE_UPDATE_FINALCALL();
           } else {
             // get receiver
             int parms = cache->parameter_size();
             // Same comments as invokevirtual apply here
-            VERIFY_OOP(STACK_OBJECT(-parms));
-            InstanceKlass* rcvrKlass = (InstanceKlass*)
-                                 STACK_OBJECT(-parms)->klass();
+            oop rcvr = STACK_OBJECT(-parms);
+            VERIFY_OOP(rcvr);
+            InstanceKlass* rcvrKlass = (InstanceKlass*)rcvr->klass();
             callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
+            // Profile 'special case of invokeinterface' virtual call.
+            BI_PROFILE_UPDATE_VIRTUALCALL(rcvr->klass());
           }
           istate->set_callee(callee);
           istate->set_callee_entry_point(callee->from_interpreted_entry());
@@ -2486,15 +2593,18 @@
         // interface.  The link resolver checks this but only for the first
         // time this interface is called.
         if (i == int2->itable_length()) {
-          VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "");
+          VM_JAVA_ERROR(vmSymbols::java_lang_IncompatibleClassChangeError(), "", note_no_trap);
         }
         int mindex = cache->f2_as_index();
         itableMethodEntry* im = ki->first_method_entry(rcvr->klass());
         callee = im[mindex].method();
         if (callee == NULL) {
-          VM_JAVA_ERROR(vmSymbols::java_lang_AbstractMethodError(), "");
+          VM_JAVA_ERROR(vmSymbols::java_lang_AbstractMethodError(), "", note_no_trap);
         }
 
+        // Profile virtual call.
+        BI_PROFILE_UPDATE_VIRTUALCALL(rcvr->klass());
+
         istate->set_callee(callee);
         istate->set_callee_entry_point(callee->from_interpreted_entry());
 #ifdef VM_JVMTI
@@ -2526,8 +2636,11 @@
           Method* callee;
           if ((Bytecodes::Code)opcode == Bytecodes::_invokevirtual) {
             CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
-            if (cache->is_vfinal()) callee = cache->f2_as_vfinal_method();
-            else {
+            if (cache->is_vfinal()) {
+              callee = cache->f2_as_vfinal_method();
+              // Profile final call.
+              BI_PROFILE_UPDATE_FINALCALL();
+            } else {
               // get receiver
               int parms = cache->parameter_size();
               // this works but needs a resourcemark and seems to create a vtable on every call:
@@ -2536,8 +2649,9 @@
               // this fails with an assert
               // InstanceKlass* rcvrKlass = InstanceKlass::cast(STACK_OBJECT(-parms)->klass());
               // but this works
-              VERIFY_OOP(STACK_OBJECT(-parms));
-              InstanceKlass* rcvrKlass = (InstanceKlass*) STACK_OBJECT(-parms)->klass();
+              oop rcvr = STACK_OBJECT(-parms);
+              VERIFY_OOP(rcvr);
+              InstanceKlass* rcvrKlass = (InstanceKlass*)rcvr->klass();
               /*
                 Executing this code in java.lang.String:
                     public String(char value[]) {
@@ -2555,12 +2669,17 @@
 
               */
               callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
+              // Profile virtual call.
+              BI_PROFILE_UPDATE_VIRTUALCALL(rcvr->klass());
             }
           } else {
             if ((Bytecodes::Code)opcode == Bytecodes::_invokespecial) {
               CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
             }
             callee = cache->f1_as_method();
+
+            // Profile call.
+            BI_PROFILE_UPDATE_CALL();
           }
 
           istate->set_callee(callee);
@@ -2612,6 +2731,8 @@
       CASE(_goto):
       {
           int16_t offset = (int16_t)Bytes::get_Java_u2(pc + 1);
+          // Profile jump.
+          BI_PROFILE_UPDATE_JUMP();
           address branch_pc = pc;
           UPDATE_PC(offset);
           DO_BACKEDGE_CHECKS(offset, branch_pc);
@@ -2628,6 +2749,8 @@
       CASE(_goto_w):
       {
           int32_t offset = Bytes::get_Java_u4(pc + 1);
+          // Profile jump.
+          BI_PROFILE_UPDATE_JUMP();
           address branch_pc = pc;
           UPDATE_PC(offset);
           DO_BACKEDGE_CHECKS(offset, branch_pc);
@@ -2637,6 +2760,9 @@
       /* return from a jsr or jsr_w */
 
       CASE(_ret): {
+          // Profile ret.
+          BI_PROFILE_UPDATE_RET(/*bci=*/((int)(intptr_t)(LOCALS_ADDR(pc[1]))));
+          // now, update the pc
           pc = istate->method()->code_base() + (intptr_t)(LOCALS_ADDR(pc[1]));
           UPDATE_PC_AND_CONTINUE(0);
       }
@@ -2718,6 +2844,9 @@
       }
       // for AbortVMOnException flag
       NOT_PRODUCT(Exceptions::debug_check_abort(except_oop));
+
+      // Update profiling data.
+      BI_PROFILE_ALIGN_TO_CURRENT_BCI();
       goto run;
     }
     if (TraceExceptions) {
@@ -2920,7 +3049,7 @@
           oop rcvr = base->obj();
           if (rcvr == NULL) {
             if (!suppress_error) {
-              VM_JAVA_ERROR_NO_JUMP(vmSymbols::java_lang_NullPointerException(), "");
+              VM_JAVA_ERROR_NO_JUMP(vmSymbols::java_lang_NullPointerException(), "", note_nullCheck_trap);
               illegal_state_oop = THREAD->pending_exception();
               THREAD->clear_pending_exception();
             }
@@ -3008,7 +3137,7 @@
     // A pending exception that was pending prior to a possible popping frame
     // overrides the popping frame.
     //
-    assert(!suppress_error || suppress_error && illegal_state_oop() == NULL, "Error was not suppressed");
+    assert(!suppress_error || (suppress_error && illegal_state_oop() == NULL), "Error was not suppressed");
     if (illegal_state_oop() != NULL || original_exception() != NULL) {
       // inform the frame manager we have no result
       istate->set_msg(throwing_exception);
diff -r 738d32552a96 src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp	Fri Jun 28 14:34:21 2013 +0200
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 SAP AG. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This file defines a set of macros which are used by the c++-interpreter
+// for updating a method's methodData object.
+
+
+#ifndef SHARE_VM_INTERPRETER_BYTECODEINTERPRETERPROFILING_HPP
+#define SHARE_VM_INTERPRETER_BYTECODEINTERPRETERPROFILING_HPP
+
+
+// Global settings /////////////////////////////////////////////////////////////
+
+
+// Enables profiling support
+#if defined(COMPILER2) && defined(PPC64)
+#define CC_INTERP_PROFILE
+#endif
+
+// Enables assertions for profiling code (also works in product-builds).
+// #define CC_INTERP_PROFILE_WITH_ASSERTIONS
+
+
+#ifdef CC_INTERP
+
+// Empty dummy implementations if profiling code is switched off. //////////////
+
+#ifndef CC_INTERP_PROFILE
+
+#define SET_MDX(mdx)
+
+#define BI_PROFILE_GET_OR_CREATE_METHOD_DATA(exception_handler)                \
+  if (ProfileInterpreter) {                                                    \
+    ShouldNotReachHere();                                                      \
+  }
+
+#define BI_PROFILE_ALIGN_TO_CURRENT_BCI()
+
+#define BI_PROFILE_UPDATE_JUMP()
+#define BI_PROFILE_UPDATE_BRANCH(is_taken)
+#define BI_PROFILE_UPDATE_RET(bci)
+#define BI_PROFILE_SUBTYPECHECK_FAILED(receiver)
+#define BI_PROFILE_UPDATE_CHECKCAST(null_seen, receiver)
+#define BI_PROFILE_UPDATE_INSTANCEOF(null_seen, receiver)
+#define BI_PROFILE_UPDATE_CALL()
+#define BI_PROFILE_UPDATE_FINALCALL()
+#define BI_PROFILE_UPDATE_VIRTUALCALL(receiver)
+#define BI_PROFILE_UPDATE_SWITCH(switch_index)
+
+
+#else
+
+
+// Non-dummy implementations ///////////////////////////////////////////////////
+
+// Accessors for the current method data pointer 'mdx'.
+#define MDX()        (istate->mdx())
+#define SET_MDX(mdx)                                                           \
+  if (TraceProfileInterpreter) {                                               \
+    /* Let it look like TraceBytecodes' format. */                             \
+    tty->print_cr("[%d]           %4d  "                                       \
+                  "mdx " PTR_FORMAT "(%d)"                                     \
+                  "  "                                                         \
+                  " \t-> " PTR_FORMAT "(%d)",                                  \
+                (int) THREAD->osthread()->thread_id(),                         \
+                BCI(),                                                         \
+                MDX(),                                                         \
+                (MDX() == NULL                                                 \
+                 ? 0                                                           \
+                 : istate->method()->method_data()->dp_to_di((address)MDX())), \
+                mdx,                                                           \
+                istate->method()->method_data()->dp_to_di((address)mdx)        \
+                );                                                             \
+  };                                                                           \
+  istate->set_mdx(mdx);
+
+
+// Dumps the profiling method data for the current method.
+#ifdef PRODUCT
+#define BI_PROFILE_PRINT_METHOD_DATA()
+#else  // PRODUCT
+#define BI_PROFILE_PRINT_METHOD_DATA()                                         \
+  {                                                                            \
+    ttyLocker ttyl;                                                            \
+    MethodData *md = istate->method()->method_data();                          \
+    tty->cr();                                                                 \
+    tty->print("method data at mdx " PTR_FORMAT "(0) for",                     \
+               md->data_layout_at(md->bci_to_di(0)));                          \
+    istate->method()->print_short_name(tty);                                   \
+    tty->cr();                                                                 \
+    if (md != NULL) {                                                          \
+      md->print_data_on(tty);                                                  \
+      address mdx = (address) MDX();                                           \
+      if (mdx != NULL) {                                                       \
+        tty->print_cr("current mdx " PTR_FORMAT "(%d)",                        \
+                      mdx,                                                     \
+                      istate->method()->method_data()->dp_to_di(mdx));         \
+      }                                                                        \
+    } else {                                                                   \
+      tty->print_cr("no method data");                                         \
+    }                                                                          \
+  }
+#endif // PRODUCT
+
+
+// Gets or creates the profiling method data and initializes mdx.
+#define BI_PROFILE_GET_OR_CREATE_METHOD_DATA(exception_handler)                \
+  if (ProfileInterpreter && MDX() == NULL) {                                   \
+    /* Mdx is not yet initialized for this activation. */                      \
+    MethodData *md = istate->method()->method_data();                          \
+    if (md == NULL) {                                                          \
+      MethodCounters* mcs;                                                     \
+      GET_METHOD_COUNTERS(mcs);                                                \
+      /* The profiling method data doesn't exist for this method, */           \
+      /* create it if the counters have overflowed. */                         \
+      if (mcs->invocation_counter()                                            \
+                         ->reached_ProfileLimit(mcs->backedge_counter())) {    \
+        /* Must use CALL_VM, because an async exception may be pending. */     \
+        CALL_VM((InterpreterRuntime::profile_method(THREAD)),                  \
+                exception_handler);                                            \
+        md = istate->method()->method_data();                                  \
+        if (md != NULL) {                                                      \
+          if (TraceProfileInterpreter) {                                       \
+            BI_PROFILE_PRINT_METHOD_DATA();                                    \
+          }                                                                    \
+          Method *m = istate->method();                                        \
+          int bci = m->bci_from(pc);                                           \
+          jint di = md->bci_to_di(bci);                                        \
+          SET_MDX(md->data_layout_at(di));                                     \
+        }                                                                      \
+      }                                                                        \
+    } else {                                                                   \
+      /* The profiling method data exists, align the method data pointer */    \
+      /* mdx to the current bytecode index. */                                 \
+      if (TraceProfileInterpreter) {                                           \
+        BI_PROFILE_PRINT_METHOD_DATA();                                        \
+      }                                                                        \
+      SET_MDX(md->data_layout_at(md->bci_to_di(BCI())));                       \
+    }                                                                          \
+  }
+
+
+// Asserts that the current method data pointer mdx corresponds
+// to the current bytecode.
+#if defined(CC_INTERP_PROFILE_WITH_ASSERTIONS)
+#define BI_PROFILE_CHECK_MDX()                                                 \
+  {                                                                            \
+    MethodData *md = istate->method()->method_data();                          \
+    address mdx  = (address) MDX();                                            \
+    address mdx2 = (address) md->data_layout_at(md->bci_to_di(BCI()));         \
+    guarantee(md  != NULL, "1");                                               \
+    guarantee(mdx  != NULL, "2");                                              \
+    guarantee(mdx2 != NULL, "3");                                              \
+    if (mdx != mdx2) {                                                         \
+      BI_PROFILE_PRINT_METHOD_DATA();                                          \
+      fatal3("invalid mdx at bci %d:"                                          \
+             " was " PTR_FORMAT                                                \
+             " but expected " PTR_FORMAT,                                      \
+             BCI(),                                                            \
+             mdx,                                                              \
+             mdx2);                                                            \
+    }                                                                          \
+  }
+#else
+#define BI_PROFILE_CHECK_MDX()
+#endif
+
+
+// Aligns the method data pointer mdx to the current bytecode index.
+#define BI_PROFILE_ALIGN_TO_CURRENT_BCI()                                      \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    MethodData *md = istate->method()->method_data();                          \
+    SET_MDX(md->data_layout_at(md->bci_to_di(BCI())));                         \
+  }
+
+
+// Updates profiling data for a jump.
+#define BI_PROFILE_UPDATE_JUMP()                                               \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    JumpData::increment_taken_count_no_overflow(MDX());                        \
+    /* Remember last branch taken count. */                                    \
+    mdo_last_branch_taken_count = JumpData::taken_count(MDX());                \
+    SET_MDX(JumpData::advance_taken(MDX()));                                   \
+  }
+
+
+// Updates profiling data for a taken/not taken branch.
+#define BI_PROFILE_UPDATE_BRANCH(is_taken)                                     \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    if (is_taken) {                                                            \
+      BranchData::increment_taken_count_no_overflow(MDX());                    \
+      /* Remember last branch taken count. */                                  \
+      mdo_last_branch_taken_count = BranchData::taken_count(MDX());            \
+      SET_MDX(BranchData::advance_taken(MDX()));                               \
+    } else {                                                                   \
+      BranchData::increment_not_taken_count_no_overflow(MDX());                \
+      SET_MDX(BranchData::advance_not_taken(MDX()));                           \
+    }                                                                          \
+  }
+
+
+// Updates profiling data for a ret with given bci.
+#define BI_PROFILE_UPDATE_RET(bci)                                             \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    MethodData *md = istate->method()->method_data();                          \
+/* FIXME: there is more to do here than increment and advance(mdx)! */         \
+    CounterData::increment_count_no_overflow(MDX());                           \
+    SET_MDX(RetData::advance(md, bci));                                        \
+  }
+
+// Decrement counter at checkcast if the subtype check fails (as template
+// interpreter does!).
+#define BI_PROFILE_SUBTYPECHECK_FAILED(receiver)                               \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    ReceiverTypeData::increment_receiver_count_no_overflow(MDX(), receiver);   \
+    ReceiverTypeData::decrement_count(MDX());                                  \
+  }
+
+// Updates profiling data for a checkcast (was a null seen? which receiver?).
+#define BI_PROFILE_UPDATE_CHECKCAST(null_seen, receiver)                       \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    if (null_seen) {                                                           \
+      ReceiverTypeData::set_null_seen(MDX());                                  \
+    } else {                                                                   \
+      /* Template interpreter doesn't increment count. */                      \
+      /* ReceiverTypeData::increment_count_no_overflow(MDX());*/               \
+      ReceiverTypeData::increment_receiver_count_no_overflow(MDX(), receiver); \
+    }                                                                          \
+    SET_MDX(ReceiverTypeData::advance(MDX()));                                 \
+  }
+
+
+// Updates profiling data for an instanceof (was a null seen? which receiver?).
+#define BI_PROFILE_UPDATE_INSTANCEOF(null_seen, receiver)                      \
+  BI_PROFILE_UPDATE_CHECKCAST(null_seen, receiver)
+
+
+// Updates profiling data for a call.
+#define BI_PROFILE_UPDATE_CALL()                                               \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    CounterData::increment_count_no_overflow(MDX());                           \
+    SET_MDX(CounterData::advance(MDX()));                                      \
+  }
+
+
+// Updates profiling data for a final call.
+#define BI_PROFILE_UPDATE_FINALCALL()                                          \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    VirtualCallData::increment_count_no_overflow(MDX());                       \
+    SET_MDX(VirtualCallData::advance(MDX()));                                  \
+  }
+
+
+// Updates profiling data for a virtual call with given receiver Klass.
+#define BI_PROFILE_UPDATE_VIRTUALCALL(receiver)                                \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    VirtualCallData::increment_receiver_count_no_overflow(MDX(), receiver);    \
+    SET_MDX(VirtualCallData::advance(MDX()));                                  \
+  }
+
+
+// Updates profiling data for a switch (tabelswitch or lookupswitch) with
+// given taken index (-1 means default case was taken).
+#define BI_PROFILE_UPDATE_SWITCH(switch_index)                                 \
+  if (ProfileInterpreter && MDX() != NULL) {                                   \
+    BI_PROFILE_CHECK_MDX();                                                    \
+    MultiBranchData::increment_count_no_overflow(MDX(), switch_index);         \
+    SET_MDX(MultiBranchData::advance(MDX(), switch_index));                    \
+  }
+
+
+// The end /////////////////////////////////////////////////////////////////////
+
+#endif // CC_INTERP_PROFILE
+
+#endif // CC_INTERP
+
+#endif // SHARE_VM_INTERPRETER_BYTECODECINTERPRETERPROFILING_HPP
diff -r 738d32552a96 src/share/vm/interpreter/interpreterRuntime.cpp
--- a/src/share/vm/interpreter/interpreterRuntime.cpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/interpreter/interpreterRuntime.cpp	Fri Jun 28 14:34:21 2013 +0200
@@ -267,6 +267,49 @@
   }
 }
 
+#ifdef CC_INTERP
+// As legacy note_trap, but we have more arguments.
+IRT_ENTRY(void, InterpreterRuntime::note_trap(JavaThread* thread, int reason, Method *method, int trap_bci))
+  methodHandle trap_method(method);
+
+  // START derived from note_trap
+  // passed as arg: methodHandle trap_method(thread, method(thread));
+  if (trap_method.not_null()) {
+    MethodData *trap_md = trap_method->method_data();
+    if (trap_md == NULL) {
+      Method::build_interpreter_method_data(trap_method, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here");
+        CLEAR_PENDING_EXCEPTION;
+      }
+      trap_md = trap_method->method_data();
+      // and fall through...
+    }
+    if (trap_md != NULL) {
+      // Update per-method count of trap events. The interpreter
+      // is updating the MDO to simulate the effect of compiler traps.
+      // Passed as arg int trap_bci = trap_method->bci_from(bcp(thread));
+      Deoptimization::update_method_data_from_interpreter(trap_md, trap_bci, reason);
+    }
+  }
+  // END derived from note_trap
+IRT_END
+
+// Class Deoptimization is not visible in BytecodeInterpreter, so we need a wrapper
+// for each exception.
+void InterpreterRuntime::note_nullCheck_trap(JavaThread* thread, Method *method, int trap_bci)
+  { if (ProfileTraps) note_trap(thread, Deoptimization::Reason_null_check, method, trap_bci); }
+void InterpreterRuntime::note_div0Check_trap(JavaThread* thread, Method *method, int trap_bci)
+  { if (ProfileTraps) note_trap(thread, Deoptimization::Reason_div0_check, method, trap_bci); }
+void InterpreterRuntime::note_rangeCheck_trap(JavaThread* thread, Method *method, int trap_bci)
+  { if (ProfileTraps) note_trap(thread, Deoptimization::Reason_range_check, method, trap_bci); }
+void InterpreterRuntime::note_classCheck_trap(JavaThread* thread, Method *method, int trap_bci)
+  { if (ProfileTraps) note_trap(thread, Deoptimization::Reason_class_check, method, trap_bci); }
+void InterpreterRuntime::note_arrayCheck_trap(JavaThread* thread, Method *method, int trap_bci)
+  { if (ProfileTraps) note_trap(thread, Deoptimization::Reason_array_check, method, trap_bci); }
+#endif // CC_INTERP
+
+
 static Handle get_preinitialized_exception(Klass* k, TRAPS) {
   // get klass
   InstanceKlass* klass = InstanceKlass::cast(k);
diff -r 738d32552a96 src/share/vm/interpreter/interpreterRuntime.hpp
--- a/src/share/vm/interpreter/interpreterRuntime.hpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/interpreter/interpreterRuntime.hpp	Fri Jun 28 14:34:21 2013 +0200
@@ -67,6 +67,10 @@
   static ConstantPoolCacheEntry* cache_entry_at(JavaThread *thread, int i)  { return method(thread)->constants()->cache()->entry_at(i); }
   static ConstantPoolCacheEntry* cache_entry(JavaThread *thread)            { return cache_entry_at(thread, Bytes::get_native_u2(bcp(thread) + 1)); }
   static void      note_trap(JavaThread *thread, int reason, TRAPS);
+#ifdef CC_INTERP
+  // Profile traps in C++ interpreter.
+  static void      note_trap(JavaThread* thread, int reason, Method *method, int trap_bci);
+#endif // CC_INTERP
 
   // Inner work method for Interpreter's frequency counter overflow
   static nmethod* frequency_counter_overflow_inner(JavaThread* thread, address branch_bcp);
@@ -97,6 +101,17 @@
   static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
   static void    throw_pending_exception(JavaThread* thread);
 
+#ifdef CC_INTERP
+  // Profile traps in C++ interpreter
+  static void    note_nullCheck_trap (JavaThread* thread, Method *method, int trap_bci);
+  static void    note_div0Check_trap (JavaThread* thread, Method *method, int trap_bci);
+  static void    note_rangeCheck_trap(JavaThread* thread, Method *method, int trap_bci);
+  static void    note_classCheck_trap(JavaThread* thread, Method *method, int trap_bci);
+  static void    note_arrayCheck_trap(JavaThread* thread, Method *method, int trap_bci);
+  // A dummy for makros that shall not profile traps
+  static void    note_no_trap(JavaThread* thread, Method *method, int trap_bci) {}
+#endif // CC_INTERP
+
   // Statics & fields
   static void    resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode);
 
diff -r 738d32552a96 src/share/vm/interpreter/invocationCounter.hpp
--- a/src/share/vm/interpreter/invocationCounter.hpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/interpreter/invocationCounter.hpp	Fri Jun 28 14:34:21 2013 +0200
@@ -101,13 +101,17 @@
 
   // Test counter using scaled limits like the asm interpreter would do rather than doing
   // the shifts to normalize the counter.
-
-  bool   reached_InvocationLimit() const         { return _counter >= (unsigned int) InterpreterInvocationLimit; }
-  bool   reached_BackwardBranchLimit() const     { return _counter >= (unsigned int) InterpreterBackwardBranchLimit; }
+  // Checks sum of invocation_counter and backedge_counter as the template interpreter does.
+  bool reached_InvocationLimit(InvocationCounter *back_edge_count) const {
+    return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterInvocationLimit;
+  }
+  bool reached_BackwardBranchLimit(InvocationCounter *back_edge_count) const {
+    return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterBackwardBranchLimit;
+  }
 
   // Do this just like asm interpreter does for max speed
-  bool   reached_ProfileLimit(InvocationCounter *back_edge_count) const {
-    return (_counter && count_mask) + back_edge_count->_counter >= (unsigned int) InterpreterProfileLimit;
+  bool reached_ProfileLimit(InvocationCounter *back_edge_count) const {
+    return (_counter & count_mask) + (back_edge_count->_counter & count_mask) >= (unsigned int) InterpreterProfileLimit;
   }
 
   void increment()                               { _counter += count_increment; }
diff -r 738d32552a96 src/share/vm/oops/methodData.cpp
--- a/src/share/vm/oops/methodData.cpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/oops/methodData.cpp	Fri Jun 28 14:34:21 2013 +0200
@@ -244,6 +244,11 @@
   return mdp;
 }
 
+#ifdef CC_INTERP
+DataLayout* RetData::advance(MethodData *md, int bci) {
+  return (DataLayout*) md->bci_to_dp(bci);
+}
+#endif // CC_INTERP
 
 #ifndef PRODUCT
 void RetData::print_data_on(outputStream* st) {
diff -r 738d32552a96 src/share/vm/oops/methodData.hpp
--- a/src/share/vm/oops/methodData.hpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/oops/methodData.hpp	Fri Jun 28 14:34:21 2013 +0200
@@ -225,6 +225,11 @@
   static ByteSize cell_offset(int index) {
     return byte_offset_of(DataLayout, _cells) + in_ByteSize(index * cell_size);
   }
+#ifdef CC_INTERP
+  static int cell_offset_in_bytes(int index) {
+    return (int)offset_of(DataLayout, _cells[index]);
+  }
+#endif // CC_INTERP
   // Return a value which, when or-ed as a byte into _flags, sets the flag.
   static int flag_number_to_byte_constant(int flag_number) {
     assert(0 <= flag_number && flag_number < flag_limit, "oob");
@@ -356,6 +361,41 @@
     _data = data;
   }
 
+#ifdef CC_INTERP
+  // Static low level accessors for DataLayout with ProfileData's semantics.
+
+  static int cell_offset_in_bytes(int index) {
+    return DataLayout::cell_offset_in_bytes(index);
+  }
+
+  static void increment_uint_at_no_overflow(DataLayout* layout, int index,
+                                            int inc = DataLayout::counter_increment) {
+    uint count = ((uint)layout->cell_at(index)) + inc;
+    if (count == 0) return;
+    layout->set_cell_at(index, (intptr_t) count);
+  }
+
+  static int int_at(DataLayout* layout, int index) {
+    return (int)layout->cell_at(index);
+  }
+
+  static int uint_at(DataLayout* layout, int index) {
+    return (uint)layout->cell_at(index);
+  }
+
+  static oop oop_at(DataLayout* layout, int index) {
+    return (oop)layout->cell_at(index);
+  }
+
+  static void set_intptr_at(DataLayout* layout, int index, intptr_t value) {
+    layout->set_cell_at(index, (intptr_t) value);
+  }
+
+  static void set_flag_at(DataLayout* layout, int flag_number) {
+    layout->set_flag_at(flag_number);
+  }
+#endif // CC_INTERP
+
 public:
   // Constructor for invalid ProfileData.
   ProfileData();
@@ -495,6 +535,20 @@
     return cell_offset(bit_cell_count);
   }
 
+#ifdef CC_INTERP
+  static int bit_data_size_in_bytes() {
+    return cell_offset_in_bytes(bit_cell_count);
+  }
+
+  static void set_null_seen(DataLayout* layout) {
+    set_flag_at(layout, null_seen_flag);
+  }
+
+  static DataLayout* advance(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)BitData::bit_data_size_in_bytes());
+  }
+#endif // CC_INTERP
+
 #ifndef PRODUCT
   void print_data_on(outputStream* st);
 #endif
@@ -539,6 +593,25 @@
     set_uint_at(count_off, count);
   }
 
+#ifdef CC_INTERP
+  static int counter_data_size_in_bytes() {
+    return cell_offset_in_bytes(counter_cell_count);
+  }
+
+  static void increment_count_no_overflow(DataLayout* layout) {
+    increment_uint_at_no_overflow(layout, count_off);
+  }
+
+  // Support counter decrementation at checkcast / subtype check failed
+  static void decrement_count(DataLayout* layout) {
+    increment_uint_at_no_overflow(layout, count_off, -1);
+  }
+
+  static DataLayout* advance(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)CounterData::counter_data_size_in_bytes());
+  }
+#endif // CC_INTERP
+
 #ifndef PRODUCT
   void print_data_on(outputStream* st);
 #endif
@@ -609,6 +682,20 @@
     return cell_offset(displacement_off_set);
   }
 
+#ifdef CC_INTERP
+  static void increment_taken_count_no_overflow(DataLayout* layout) {
+    increment_uint_at_no_overflow(layout, taken_off_set);
+  }
+
+  static DataLayout* advance_taken(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)int_at(layout, displacement_off_set));
+  }
+
+  static uint taken_count(DataLayout* layout) {
+    return (uint) uint_at(layout, taken_off_set);
+  }
+#endif // CC_INTERP
+
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -718,6 +805,43 @@
   // GC support
   virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
 
+#ifdef CC_INTERP
+  static int receiver_type_data_size_in_bytes() {
+    return cell_offset_in_bytes(static_cell_count());
+  }
+
+  static Klass *receiver_unchecked(DataLayout* layout, uint row) {
+    oop recv = oop_at(layout, receiver_cell_index(row));
+    return (Klass *)recv;
+  }
+
+  static void increment_receiver_count_no_overflow(DataLayout* layout, Klass *rcvr) {
+    const int num_rows = row_limit();
+    // Receiver already exists?
+    for (int row = 0; row < num_rows; row++) {
+      if (receiver_unchecked(layout, row) == rcvr) {
+        increment_uint_at_no_overflow(layout, receiver_count_cell_index(row));
+        return;
+      }
+    }
+    // New receiver, find a free slot.
+    for (int row = 0; row < num_rows; row++) {
+      if (receiver_unchecked(layout, row) == NULL) {
+        set_intptr_at(layout, receiver_cell_index(row), (intptr_t)rcvr);
+        increment_uint_at_no_overflow(layout, receiver_count_cell_index(row));
+        return;
+      }
+    }
+    // Receiver did not match any saved receiver and there is no empty row for it.
+    // Increment total counter to indicate polymorphic case.
+    increment_count_no_overflow(layout);
+  }
+
+  static DataLayout* advance(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)ReceiverTypeData::receiver_type_data_size_in_bytes());
+  }
+#endif // CC_INTERP
+
 #ifndef PRODUCT
   void print_receiver_data_on(outputStream* st);
   void print_data_on(outputStream* st);
@@ -751,6 +875,16 @@
     return cell_offset(static_cell_count());
   }
 
+#ifdef CC_INTERP
+  static int virtual_call_data_size_in_bytes() {
+    return cell_offset_in_bytes(static_cell_count());
+  }
+
+  static DataLayout* advance(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)VirtualCallData::virtual_call_data_size_in_bytes());
+  }
+#endif // CC_INTERP
+
 #ifndef PRODUCT
   void print_data_on(outputStream* st);
 #endif
@@ -847,6 +981,10 @@
     return cell_offset(bci_displacement_cell_index(row));
   }
 
+#ifdef CC_INTERP
+  static DataLayout* advance(MethodData *md, int bci);
+#endif // CC_INTERP
+
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -911,6 +1049,20 @@
     return cell_offset(branch_cell_count);
   }
 
+#ifdef CC_INTERP
+  static int branch_data_size_in_bytes() {
+    return cell_offset_in_bytes(branch_cell_count);
+  }
+
+  static void increment_not_taken_count_no_overflow(DataLayout* layout) {
+    increment_uint_at_no_overflow(layout, not_taken_off_set);
+  }
+
+  static DataLayout* advance_not_taken(DataLayout* layout) {
+    return (DataLayout*) (((address)layout) + (ssize_t)BranchData::branch_data_size_in_bytes());
+  }
+#endif // CC_INTERP
+
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -950,6 +1102,20 @@
     set_int_at(aindex, value);
   }
 
+#ifdef CC_INTERP
+  // Static low level accessors for DataLayout with ArrayData's semantics.
+
+  static void increment_array_uint_at_no_overflow(DataLayout* layout, int index) {
+    int aindex = index + array_start_off_set;
+    increment_uint_at_no_overflow(layout, aindex);
+  }
+
+  static int array_int_at(DataLayout* layout, int index) {
+    int aindex = index + array_start_off_set;
+    return int_at(layout, aindex);
+  }
+#endif // CC_INTERP
+
   // Code generation support for subclasses.
   static ByteSize array_element_offset(int index) {
     return cell_offset(array_start_off_set + index);
@@ -1068,6 +1234,28 @@
     return in_ByteSize(relative_displacement_off_set) * cell_size;
   }
 
+#ifdef CC_INTERP
+  static void increment_count_no_overflow(DataLayout* layout, int index) {
+    if (index == -1) {
+      increment_array_uint_at_no_overflow(layout, default_count_off_set);
+    } else {
+      increment_array_uint_at_no_overflow(layout, case_array_start +
+                                                  index * per_case_cell_count +
+                                                  relative_count_off_set);
+    }
+  }
+
+  static DataLayout* advance(DataLayout* layout, int index) {
+    if (index == -1) {
+      return (DataLayout*) (((address)layout) + (ssize_t)array_int_at(layout, default_disaplacement_off_set));
+    } else {
+      return (DataLayout*) (((address)layout) + (ssize_t)array_int_at(layout, case_array_start +
+                                                                              index * per_case_cell_count +
+                                                                              relative_displacement_off_set));
+    }
+  }
+#endif // CC_INTERP
+
   // Specific initialization.
   void post_initialize(BytecodeStream* stream, MethodData* mdo);
 
@@ -1146,8 +1334,11 @@
 // adjusted in the event of a change in control flow.
 //
 
+CC_INTERP_ONLY(class BytecodeInterpreter;)
+
 class MethodData : public Metadata {
   friend class VMStructs;
+  CC_INTERP_ONLY(friend class BytecodeInterpreter;)
 private:
   friend class ProfileData;
 
diff -r 738d32552a96 src/share/vm/runtime/arguments.cpp
--- a/src/share/vm/runtime/arguments.cpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/runtime/arguments.cpp	Fri Jun 28 14:34:21 2013 +0200
@@ -3578,10 +3578,10 @@
   // Clear flags not supported by the C++ interpreter
 #if !defined(PPC64)
   FLAG_SET_DEFAULT(UseBiasedLocking, false);
+  FLAG_SET_DEFAULT(ProfileInterpreter, false);
   LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedOops, false));
   LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedKlassPointers, false));
 #endif // !PPC64
-  FLAG_SET_DEFAULT(ProfileInterpreter, false);
 #endif // CC_INTERP
 
 #ifdef COMPILER2
diff -r 738d32552a96 src/share/vm/runtime/globals.hpp
--- a/src/share/vm/runtime/globals.hpp	Fri Jun 28 14:17:32 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Fri Jun 28 14:34:21 2013 +0200
@@ -2712,6 +2712,9 @@
   product_pd(bool, ProfileInterpreter,                                      \
            "Profile at the bytecode level during interpretation")           \
                                                                             \
+  develop(bool, TraceProfileInterpreter, false,                             \
+           "Trace profiling at the bytecode level during interpretation")   \
+                                                                            \
   develop_pd(bool, ProfileTraps,                                            \
           "Profile deoptimization traps at the bytecode level")             \
                                                                             \