src/share/vm/interpreter/bytecodeInterpreter.cpp
Print this page
rev 5190 : 8024468: PPC64 (part 201): cppInterpreter: implement bytecode profiling
Summary: Implement profiling for c2 jit compilation. Also enable new cppInterpreter features.
@@ -26,10 +26,11 @@
#include "classfile/vmSymbols.hpp"
#include "gc_interface/collectedHeap.hpp"
#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"
#include "oops/methodCounters.hpp"
#include "oops/objArrayKlass.hpp"
@@ -140,23 +141,24 @@
* VM_JAVA_ERROR - Macro for throwing a java exception from
* the interpreter loop. Should really be a CALL_VM but there
* 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
#define DO_UPDATE_INSTRUCTION_COUNT(opcode)
#else
@@ -338,11 +340,27 @@
MethodCounters* mcs; \
GET_METHOD_COUNTERS(mcs); \
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); \
if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \
intptr_t* buf; \
@@ -353,11 +371,10 @@
istate->set_osr_entry(osr_nmethod->osr_entry()); \
return; \
} \
} \
} /* UseCompiler ... */ \
- mcs->invocation_counter()->increment(); \
SAFEPOINT; \
}
/*
* For those opcodes that need to have a GC point on a backwards branch
@@ -386,19 +403,23 @@
#define CACHE_CP() cp = istate->constants();
#define CACHE_LOCALS() locals = istate->locals();
#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(), ""); \
+ VM_JAVA_ERROR(vmSymbols::java_lang_NullPointerException(), "", note_nullCheck_trap); \
} \
VERIFY_OOP(obj_)
#define VMdoubleConstZero() 0.0
#define VMdoubleConstOne() 1.0
@@ -633,13 +654,20 @@
guarantee(istate->msg() == initialize ||
topOfStack >= istate->stack_limit() &&
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();
#endif
return;
@@ -654,19 +682,16 @@
GET_METHOD_COUNTERS(mcs);
if (ProfileInterpreter) {
METHOD->increment_interpreter_invocation_count(THREAD);
}
mcs->invocation_counter()->increment();
- if (mcs->invocation_counter()->reached_InvocationLimit()) {
+ 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
-
- // istate->set_msg(retry_method);
- // THREAD->clr_do_not_unlock();
- // return;
+ // 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;
}
if ((istate->_stack_base - istate->_stack_limit) != istate->method()->max_stack() + 1) {
// initialize
@@ -684,22 +709,21 @@
interesting = true;
}
}
#endif // HACK
-
- // lock method if synchronized
+ // Lock method if synchronized.
if (METHOD->is_synchronized()) {
// oop rcvr = locals[0].j.r;
oop rcvr;
if (METHOD->is_static()) {
rcvr = METHOD->constants()->pool_holder()->java_mirror();
} else {
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);
bool success = false;
uintptr_t epoch_mask_in_place = (uintptr_t)markOopDesc::epoch_mask_in_place;
@@ -801,10 +825,16 @@
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
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;
}
case method_resume: {
@@ -834,17 +864,27 @@
}
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;
}
case deopt_resume2: {
// 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;
}
case deopt_resume: {
// Returned from an opcode that has completed. The stack has
@@ -863,10 +903,15 @@
// this will do the right thing even if an exception is pending.
goto handle_return;
}
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: {
// continue locking now that we have a monitor to use
// we expect to find newly allocated monitor at the "top" of the monitor stack.
@@ -1113,10 +1158,15 @@
CASE(_wide): {
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));
SET_STACK_OBJECT(LOCALS_OBJECT(reg), 0);
UPDATE_PC_AND_TOS_AND_CONTINUE(4, 1);
@@ -1156,14 +1206,17 @@
// Be nice to see what this generates.... QQQ
SET_LOCALS_INT(LOCALS_INT(reg) + offset, reg);
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);
}
}
#undef OPC_STORE_n
@@ -1240,11 +1293,11 @@
#undef OPC_INT_BINARY
#define OPC_INT_BINARY(opcname, opname, test) \
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)), \
-2); \
UPDATE_PC_AND_TOS_AND_CONTINUE(1, -1); \
@@ -1252,11 +1305,11 @@
{ \
if (test) { \
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) */ \
SET_STACK_LONG(VMlong##opname(STACK_LONG(-3), \
STACK_LONG(-1)), \
@@ -1465,52 +1518,67 @@
/* comparison operators */
#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; \
}
#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; \
}
#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; \
}
#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; \
}
COMPARISON_OP(lt, <);
@@ -1529,34 +1597,46 @@
int32_t key = STACK_INT(-1);
int32_t low = Bytes::get_Java_u4((address)&lpc[1]);
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]);
+ 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);
CONTINUE;
}
@@ -1637,11 +1717,11 @@
char message[jintAsStringSize]; \
CHECK_NULL(arrObj); \
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 */
#define ARRAY_LOADTO32(T, T2, format, stackRes, extra) \
{ \
@@ -1711,19 +1791,26 @@
VERIFY_OOP(rhsObject);
ARRAY_INTRO( -3);
// 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);
}
CASE(_bastore):
@@ -2117,10 +2204,14 @@
// If the TLAB isn't pre-zeroed then we'll have to do it
bool need_zero = !ZeroTLAB;
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:
HeapWord* compare_to = *Universe::heap()->top_addr();
@@ -2130,10 +2221,11 @@
goto retry;
}
result = (oop) compare_to;
}
}
+#endif
if (result != NULL) {
// Initialize object (if nonzero size and need) and then the header
if (need_zero ) {
HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize;
obj_size -= sizeof(oopDesc) / oopSize;
@@ -2185,65 +2277,67 @@
}
CASE(_checkcast):
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);
CASE(_ldc_w):
CASE(_ldc):
@@ -2382,10 +2476,13 @@
istate->set_msg(call_method);
istate->set_callee(method);
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...
}
CASE(_invokehandle): {
@@ -2414,10 +2511,13 @@
istate->set_msg(call_method);
istate->set_callee(method);
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...
}
CASE(_invokeinterface): {
u2 index = Bytes::get_native_u2(pc+1);
@@ -2441,18 +2541,22 @@
if (cache->is_forced_virtual()) {
Method* callee;
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());
#ifdef VM_JVMTI
if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) {
@@ -2479,19 +2583,22 @@
}
// If the interface isn't found, this class doesn't implement this
// 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
if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) {
istate->set_callee_entry_point(callee->interpreter_entry());
@@ -2519,22 +2626,26 @@
istate->set_msg(call_method);
{
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:
// Method* callee = rcvr->klass()->vtable()->method_at(cache->f2_as_index());
//
// 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[]) {
this.count = value.length;
this.value = (char[])value.clone();
@@ -2548,16 +2659,21 @@
because rcvr->klass()->oop_is_instance() == 0
However it seems to have a vtable in the right location. Huh?
*/
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);
istate->set_callee_entry_point(callee->from_interpreted_entry());
#ifdef VM_JVMTI
@@ -2605,10 +2721,12 @@
}
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);
CONTINUE;
}
@@ -2621,19 +2739,24 @@
}
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);
CONTINUE;
}
/* 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);
}
/* debugger breakpoint */
@@ -2711,10 +2834,13 @@
istate->bcp() - (intptr_t)METHOD->code_base(),
continuation_bci, THREAD);
}
// for AbortVMOnException flag
NOT_PRODUCT(Exceptions::debug_check_abort(except_oop));
+
+ // Update profiling data.
+ BI_PROFILE_ALIGN_TO_CURRENT_BCI();
goto run;
}
if (TraceExceptions) {
ttyLocker ttyl;
ResourceMark rm;
@@ -2918,11 +3044,11 @@
// and must use first monitor slot.
//
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();
}
} else if (UseHeavyMonitors) {
{
@@ -3006,13 +3132,13 @@
//
// See if we are returning any exception
// 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);
else
THREAD->set_pending_exception(original_exception(), NULL, 0);