# HG changeset patch # User goetz # Date 1379251738 -7200 # Node ID 4ddc36494fd9712c9778c787a44510bf97c16fd0 # Parent f3806614494a8f6e7865fe7dd8d29f33448db48c 8024468: PPC64 (part 201): cppInterpreter: implement bytecode profiling Summary: Implement profiling for c2 jit compilation. Also enable new cppInterpreter features. diff --git a/src/cpu/zero/vm/cppInterpreter_zero.cpp b/src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -220,7 +220,7 @@ } InvocationCounter *counter = mcs->invocation_counter(); counter->increment(); - if (counter->reached_InvocationLimit()) { + if (counter->reached_InvocationLimit(mcs->backedge_counter())) { CALL_VM_NOCHECK( InterpreterRuntime::frequency_counter_overflow(thread, NULL)); if (HAS_PENDING_EXCEPTION) diff --git a/src/share/vm/interpreter/bytecodeInterpreter.cpp b/src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -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/resourceArea.hpp" @@ -142,19 +143,20 @@ * 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); \ } \ RESET_LAST_JAVA_FRAME(); \ CACHE_STATE(); -// Normal throw of a java error -#define VM_JAVA_ERROR(name, msg) \ - VM_JAVA_ERROR_NO_JUMP(name, msg) \ +// Normal throw of a java error. +#define VM_JAVA_ERROR(name, msg, note_a_trap) \ + VM_JAVA_ERROR_NO_JUMP(name, msg, note_a_trap) \ goto handle_exception; #ifdef PRODUCT @@ -340,9 +342,25 @@ 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; \ + nmethod* osr_nmethod; \ OSR_REQUEST(osr_nmethod, branch_pc); \ if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \ intptr_t* buf; \ @@ -355,7 +373,6 @@ } \ } \ } /* UseCompiler ... */ \ - mcs->invocation_counter()->increment(); \ SAFEPOINT; \ } @@ -388,17 +405,21 @@ #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(), ""); \ - } \ - VERIFY_OOP(obj_) +#define CHECK_NULL(obj_) \ + if ((obj_) == NULL) { \ + VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), "", note_nullCheck_trap); \ + } \ + VERIFY_OOP(obj_) #define VMdoubleConstZero() 0.0 #define VMdoubleConstOne() 1.0 @@ -635,9 +656,16 @@ 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 + if (initialized++) ShouldNotReachHere(); // Only one initialize call. _compiling = (UseCompiler || CountCompiledCalls); #ifdef VM_JVMTI _jvmti_interp_events = JvmtiExport::can_post_interpreter_events(); @@ -656,15 +684,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; } @@ -686,8 +711,7 @@ } #endif // HACK - - // lock method if synchronized + // Lock method if synchronized. if (METHOD->is_synchronized()) { // oop rcvr = locals[0].j.r; oop rcvr; @@ -697,7 +721,7 @@ rcvr = LOCALS_OBJECT(0); VERIFY_OOP(rcvr); } - // The initial monitor is ours for the taking + // The initial monitor is ours for the taking. // Monitor not filled in frame manager any longer as this caused race condition with biased locking. BasicObjectLock* mon = &istate->monitor_base()[-1]; mon->set_obj(rcvr); @@ -803,6 +827,12 @@ // clear the message so we don't confuse ourselves later 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; } @@ -836,6 +866,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; } @@ -843,6 +878,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; } @@ -865,6 +905,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: { @@ -1115,6 +1160,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)); @@ -1158,10 +1208,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); } } @@ -1242,7 +1295,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)), \ @@ -1254,7 +1307,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) */ \ @@ -1467,17 +1520,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; \ @@ -1486,9 +1545,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; \ @@ -1496,9 +1558,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; \ @@ -1506,9 +1571,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; \ @@ -1531,30 +1599,42 @@ 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]); - // Does this really need a full backedge check (osr?) + 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); DO_BACKEDGE_CHECKS(skip, branch_pc); CONTINUE; } - /* Goto pc whose table entry matches specified key */ + /* Goto pc whose table entry matches specified key. */ CASE(_lookupswitch): { 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); @@ -1639,7 +1719,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 */ @@ -1713,15 +1793,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); } ((objArrayOopDesc *) arrObj)->obj_at_put(index, rhsObject); UPDATE_PC_AND_TOS_AND_CONTINUE(1, -3); @@ -2119,10 +2206,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()) { @@ -2132,6 +2223,7 @@ result = (oop) compare_to; } } +#endif if (result != NULL) { // Initialize object (if nonzero size and need) and then the header if (need_zero ) { @@ -2187,61 +2279,63 @@ 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 + // 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 + // 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); // Constant pool may have actual klass or unresolved klass. If it is - // unresolved we must resolve it + // 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(); + Klass* objKlass = STACK_OBJECT(-1)->klass(); // // Check for compatibilty. This check must not GC!! - // Seems way more expensive now that we must dispatch + // 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); @@ -2384,6 +2478,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... } @@ -2416,6 +2513,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... } @@ -2443,14 +2543,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 + // 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(); + // Same comments as invokevirtual apply here. + 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()); @@ -2481,15 +2585,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 @@ -2521,8 +2628,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: @@ -2531,8 +2641,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[]) { @@ -2550,12 +2661,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); @@ -2607,6 +2723,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); @@ -2623,6 +2741,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); @@ -2632,6 +2752,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); } @@ -2713,6 +2836,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 +3046,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,9 +3134,9 @@ // 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 + // Inform the frame manager we have no result. istate->set_msg(throwing_exception); if (illegal_state_oop() != NULL) THREAD->set_pending_exception(illegal_state_oop(), NULL, 0); diff --git a/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp b/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp new file mode 100644 --- /dev/null +++ b/src/share/vm/interpreter/bytecodeInterpreterProfiling.hpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2013 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) +#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 --git a/src/share/vm/interpreter/interpreterRuntime.cpp b/src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/src/share/vm/interpreter/interpreterRuntime.cpp @@ -241,18 +241,15 @@ //------------------------------------------------------------------------------------------------------------------------ // Exceptions -// Assume the compiler is (or will be) interested in this event. -// If necessary, create an MDO to hold the information, and record it. -void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) { - assert(ProfileTraps, "call me only if profiling"); - methodHandle trap_method(thread, method(thread)); - +void InterpreterRuntime::note_trap_inner(JavaThread* thread, int reason, + methodHandle trap_method, int trap_bci, TRAPS) { if (trap_method.not_null()) { MethodData* trap_mdo = trap_method->method_data(); if (trap_mdo == 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"); + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), + "we expect only an OOM error here"); CLEAR_PENDING_EXCEPTION; } trap_mdo = trap_method->method_data(); @@ -261,12 +258,42 @@ if (trap_mdo != NULL) { // Update per-method count of trap events. The interpreter // is updating the MDO to simulate the effect of compiler traps. - int trap_bci = trap_method->bci_from(bcp(thread)); Deoptimization::update_method_data_from_interpreter(trap_mdo, trap_bci, reason); } } } +// Assume the compiler is (or will be) interested in this event. +// If necessary, create an MDO to hold the information, and record it. +void InterpreterRuntime::note_trap(JavaThread* thread, int reason, TRAPS) { + assert(ProfileTraps, "call me only if profiling"); + methodHandle trap_method(thread, method(thread)); + int trap_bci = trap_method->bci_from(bcp(thread)); + note_trap_inner(thread, reason, trap_method, trap_bci, THREAD); +} + +#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); + note_trap_inner(thread, reason, trap_method, trap_bci, THREAD); +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 --git a/src/share/vm/interpreter/interpreterRuntime.hpp b/src/share/vm/interpreter/interpreterRuntime.hpp --- a/src/share/vm/interpreter/interpreterRuntime.hpp +++ b/src/share/vm/interpreter/interpreterRuntime.hpp @@ -66,9 +66,15 @@ 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_inner(JavaThread* thread, int reason, + methodHandle trap_method, int trap_bci, TRAPS); 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 + // Inner work method for Interpreter's frequency counter overflow. static nmethod* frequency_counter_overflow_inner(JavaThread* thread, address branch_bcp); public: @@ -100,6 +106,17 @@ #endif 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 --git a/src/share/vm/interpreter/invocationCounter.hpp b/src/share/vm/interpreter/invocationCounter.hpp --- a/src/share/vm/interpreter/invocationCounter.hpp +++ b/src/share/vm/interpreter/invocationCounter.hpp @@ -99,16 +99,24 @@ int get_BackwardBranchLimit() const { return InterpreterBackwardBranchLimit >> number_of_noncount_bits; } int get_ProfileLimit() const { return InterpreterProfileLimit >> number_of_noncount_bits; } +#ifdef CC_INTERP // 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; } - - // 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; + // 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 & count_mask) >= + (unsigned int) InterpreterProfileLimit; + } +#endif // CC_INTERP void increment() { _counter += count_increment; } diff --git a/src/share/vm/oops/methodData.cpp b/src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp +++ b/src/share/vm/oops/methodData.cpp @@ -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 --git a/src/share/vm/oops/methodData.hpp b/src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp +++ b/src/share/vm/oops/methodData.hpp @@ -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 --git a/src/share/vm/prims/jvmtiManageCapabilities.cpp b/src/share/vm/prims/jvmtiManageCapabilities.cpp --- a/src/share/vm/prims/jvmtiManageCapabilities.cpp +++ b/src/share/vm/prims/jvmtiManageCapabilities.cpp @@ -117,10 +117,10 @@ jvmtiCapabilities jc; memset(&jc, 0, sizeof(jc)); -#ifndef CC_INTERP +#ifndef ZERO jc.can_pop_frame = 1; jc.can_force_early_return = 1; -#endif // !CC_INTERP +#endif // !ZERO jc.can_get_source_debug_extension = 1; jc.can_access_local_variables = 1; jc.can_maintain_original_method_order = 1; diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -3592,8 +3592,8 @@ UseBiasedLocking = false; } -#ifdef CC_INTERP - // Clear flags not supported by the C++ interpreter +#ifdef ZERO + // Clear flags not supported on zero. FLAG_SET_DEFAULT(ProfileInterpreter, false); FLAG_SET_DEFAULT(UseBiasedLocking, false); LP64_ONLY(FLAG_SET_DEFAULT(UseCompressedOops, false)); diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -2727,6 +2727,11 @@ product_pd(bool, ProfileInterpreter, \ "Profile at the bytecode level during interpretation") \ \ + develop(bool, TraceProfileInterpreter, false, \ + "Trace profiling at the bytecode level during interpretation. " \ + "This outputs the profiling information collected to improve " \ + "jit compilation.") \ + \ develop_pd(bool, ProfileTraps, \ "Profile deoptimization traps at the bytecode level") \ \