diff --git a/vm/vmcore/include/jvmti_break_intf.h b/vm/vmcore/include/jvmti_break_intf.h index a11341b..6d14f0a 100755 --- a/vm/vmcore/include/jvmti_break_intf.h +++ b/vm/vmcore/include/jvmti_break_intf.h @@ -228,4 +228,8 @@ jvmti_process_interpreter_breakpoint_eve // Callback for JIT method compile void jvmti_set_pending_breakpoints(Method *method); +// debug function dump compiled method +void jvmti_dump_compiled_method(Method *method); + + #endif // __JVMTI_BREAK_INTF_H__ diff --git a/vm/vmcore/src/jvmti/jvmti_event.cpp b/vm/vmcore/src/jvmti/jvmti_event.cpp index 3cb412e..751ca3a 100755 --- a/vm/vmcore/src/jvmti/jvmti_event.cpp +++ b/vm/vmcore/src/jvmti/jvmti_event.cpp @@ -720,13 +720,13 @@ jvmti_process_method_exit_event(jmethodI VM_thread *curr_thread = p_TLS_vmthread; jvmti_frame_pop_listener *fpl = curr_thread->frame_pop_listener; - jint skip = 0; + jint UNREF skip; jint depth = get_thread_stack_depth(curr_thread, &skip); while (fpl) { jvmti_frame_pop_listener *next_fpl = fpl->next; - if (fpl->depth == depth + skip) + if (fpl->depth == depth) { jvmti_process_frame_pop_event( reinterpret_cast(fpl->env), @@ -756,6 +756,12 @@ jvmti_process_frame_pop_event(jvmtiEnv * jthread thread = getCurrentThread(); JNIEnv *jni_env = (JNIEnv *)jni_native_intf; + assert(method); + TRACE2("jvmti.event.popframe", "PopFrame event is called for method:" + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) ); + if (NULL != ti_env->event_table.FramePop) ti_env->event_table.FramePop(jvmti_env, jni_env, thread, method, was_popped_by_exception); diff --git a/vm/vmcore/src/jvmti/jvmti_stack.cpp b/vm/vmcore/src/jvmti/jvmti_stack.cpp index 4d7b26b..8a836c1 100755 --- a/vm/vmcore/src/jvmti/jvmti_stack.cpp +++ b/vm/vmcore/src/jvmti/jvmti_stack.cpp @@ -832,8 +832,11 @@ jvmtiNotifyFramePop(jvmtiEnv* env, vm_thread, depth); else { - StackIterator* si = si_create_from_native(vm_thread); + if (!si_get_method(si)) { + // skip VM native + si_goto_previous(si); + } jint current_depth = 0; while (!si_is_past_end(si) && current_depth < depth) { @@ -848,18 +851,14 @@ jvmtiNotifyFramePop(jvmtiEnv* env, si_free(si); return JVMTI_ERROR_OPAQUE_FRAME; } + Method* UNREF method = si_get_method(si); + si_free(si); + jint UNREF skip; + current_depth = get_thread_stack_depth(vm_thread, &skip); if (current_depth < depth) return JVMTI_ERROR_NO_MORE_FRAMES; - while (!si_is_past_end(si)) - { - if (si_get_method(si)) - current_depth += 1 + si_get_inline_depth(si); - - si_goto_previous(si); - } - jvmti_frame_pop_listener *new_listener = (jvmti_frame_pop_listener *)STD_MALLOC( sizeof(jvmti_frame_pop_listener)); @@ -869,6 +868,11 @@ jvmtiNotifyFramePop(jvmtiEnv* env, new_listener->env = reinterpret_cast(env); new_listener->next = vm_thread->frame_pop_listener; vm_thread->frame_pop_listener = new_listener; + TRACE2("jvmti.stack", "Pop listener is created: thread: " + << vm_thread << ", listener: " << new_listener + << ", env: " << new_listener->env << ", depth: " << new_listener->depth + << " -> " << class_get_name(method_get_class(method)) << "." + << method_get_name(method) << method_get_descriptor(method)); return JVMTI_ERROR_NONE; } diff --git a/vm/vmcore/src/jvmti/jvmti_step.cpp b/vm/vmcore/src/jvmti/jvmti_step.cpp index 9dbc470..7c2aade 100644 --- a/vm/vmcore/src/jvmti/jvmti_step.cpp +++ b/vm/vmcore/src/jvmti/jvmti_step.cpp @@ -422,7 +422,9 @@ jvmti_SingleStepLocation( VM_thread* thr << class_get_name(method_get_class((*next_step)[index].method)) << "." << method_get_name((*next_step)[index].method) << method_get_descriptor((*next_step)[index].method) - << " :" << (*next_step)[index].location ) + << " :" << (*next_step)[index].location << " :" + << (*next_step)[index].native_location << ", event: " + << (*next_step)[index].no_event ); } return; @@ -764,6 +766,7 @@ jvmtiError jvmti_get_next_bytecodes_from break; } + NativeCodePtr ip2 = ip; // Yes this is an invoke type bytecode if (next_location) { @@ -771,33 +774,33 @@ jvmtiError jvmti_get_next_bytecodes_from OpenExeJpdaError UNREF result = jit->get_native_location_for_bc(func, next_location, &next_ip); assert(result == EXE_ERROR_NONE); - assert(ip < next_ip); + assert(ip2 < next_ip); - VMBreakPoint *bp = vm_brpt->find_breakpoint(ip); + VMBreakPoint *bp = vm_brpt->find_breakpoint(ip2); InstructionDisassembler disasm; if (bp) disasm = *bp->disasm; else - disasm = ip; + disasm = ip2; NativeCodePtr call_ip = NULL; do { - ip = (NativeCodePtr)((POINTER_SIZE_INT)ip + disasm.get_length_with_prefix()); + ip2 = (NativeCodePtr)((POINTER_SIZE_INT)ip2 + disasm.get_length_with_prefix()); // Another thread could have instrumented this location for // prediction of invokevirtual or invokeinterface, so it is // necessary to check that location may be instrumented - uint8 b = *((uint8 *)ip); + uint8 b = *((uint8 *)ip2); if (b == INSTRUMENTATION_BYTE) { - bp = vm_brpt->find_breakpoint(ip); + bp = vm_brpt->find_breakpoint(ip2); assert(bp); disasm = *bp->disasm; } else - disasm = ip; + disasm = ip2; // Bytecode may be either invokevirtual or // invokeinterface which generate indirect calls or @@ -805,9 +808,9 @@ jvmtiError jvmti_get_next_bytecodes_from // relative calls if (disasm.get_type() == InstructionDisassembler::INDIRECT_CALL || disasm.get_type() == InstructionDisassembler::RELATIVE_CALL) - call_ip = ip; + call_ip = ip2; } - while (ip < next_ip); + while (ip2 < next_ip); // We've found no call instruction in this // bytecode. This means we're standing on the tail of @@ -816,6 +819,7 @@ jvmtiError jvmti_get_next_bytecodes_from { TRACE2("jvmti.break.ss", "SingleStep IP shifted in prediction to: " << call_ip); bc = next_location; + ip = ip2; } } // No this is not an invoke type bytecode, so the IP @@ -951,3 +955,151 @@ jvmtiError DebugUtilsTI::jvmti_single_st return JVMTI_ERROR_NONE; } + +static unsigned +jvmti_GetNextBytecodeLocation( Method *method, + unsigned location) +{ + assert( location < method->get_byte_code_size() ); + const unsigned char *bytecode = method->get_byte_code_addr(); + bool is_wide = false; + do { + switch( bytecode[location] ) + { + case OPCODE_WIDE: /* 0xc4 */ + assert( !is_wide ); + location++; + is_wide = true; + continue; + + case OPCODE_TABLESWITCH: /* 0xaa + pad + s4 * (3 + N) */ + assert( !is_wide ); + location = (location + 4)&(~0x3U); + { + int low = jvmti_GetWordValue( bytecode, location + 4 ); + int high = jvmti_GetWordValue( bytecode, location + 8 ); + return location + 4 * (high - low + 4); + } + + case OPCODE_LOOKUPSWITCH: /* 0xab + pad + s4 * 2 * (N + 1) */ + assert( !is_wide ); + location = (location + 4)&(~0x3U); + { + int number = jvmti_GetWordValue( bytecode, location + 4 ) + 1; + return location + 8 * number; + } + + case OPCODE_IINC: /* 0x84 + u1|u2 + s1|s2 */ + if( is_wide ) { + return location + 5; + } else { + return location + 3; + } + + case OPCODE_GOTO_W: /* 0xc8 + s4 */ + case OPCODE_JSR_W: /* 0xc9 + s4 */ + case OPCODE_INVOKEINTERFACE:/* 0xb9 + u2 + u1 + u1 */ + assert( !is_wide ); + return location + 5; + + case OPCODE_MULTIANEWARRAY: /* 0xc5 + u2 + u1 */ + assert( !is_wide ); + return location + 4; + + case OPCODE_ILOAD: /* 0x15 + u1|u2 */ + case OPCODE_LLOAD: /* 0x16 + u1|u2 */ + case OPCODE_FLOAD: /* 0x17 + u1|u2 */ + case OPCODE_DLOAD: /* 0x18 + u1|u2 */ + case OPCODE_ALOAD: /* 0x19 + u1|u2 */ + case OPCODE_ISTORE: /* 0x36 + u1|u2 */ + case OPCODE_LSTORE: /* 0x37 + u1|u2 */ + case OPCODE_FSTORE: /* 0x38 + u1|u2 */ + case OPCODE_DSTORE: /* 0x39 + u1|u2 */ + case OPCODE_ASTORE: /* 0x3a + u1|u2 */ + case OPCODE_RET: /* 0xa9 + u1|u2 */ + if( is_wide ) { + return location + 3; + } else { + return location + 2; + } + + case OPCODE_SIPUSH: /* 0x11 + s2 */ + case OPCODE_LDC_W: /* 0x13 + u2 */ + case OPCODE_LDC2_W: /* 0x14 + u2 */ + case OPCODE_IFEQ: /* 0x99 + s2 */ + case OPCODE_IFNE: /* 0x9a + s2 */ + case OPCODE_IFLT: /* 0x9b + s2 */ + case OPCODE_IFGE: /* 0x9c + s2 */ + case OPCODE_IFGT: /* 0x9d + s2 */ + case OPCODE_IFLE: /* 0x9e + s2 */ + case OPCODE_IF_ICMPEQ: /* 0x9f + s2 */ + case OPCODE_IF_ICMPNE: /* 0xa0 + s2 */ + case OPCODE_IF_ICMPLT: /* 0xa1 + s2 */ + case OPCODE_IF_ICMPGE: /* 0xa2 + s2 */ + case OPCODE_IF_ICMPGT: /* 0xa3 + s2 */ + case OPCODE_IF_ICMPLE: /* 0xa4 + s2 */ + case OPCODE_IF_ACMPEQ: /* 0xa5 + s2 */ + case OPCODE_IF_ACMPNE: /* 0xa6 + s2 */ + case OPCODE_GOTO: /* 0xa7 + s2 */ + case OPCODE_GETSTATIC: /* 0xb2 + u2 */ + case OPCODE_PUTSTATIC: /* 0xb3 + u2 */ + case OPCODE_GETFIELD: /* 0xb4 + u2 */ + case OPCODE_PUTFIELD: /* 0xb5 + u2 */ + case OPCODE_INVOKEVIRTUAL: /* 0xb6 + u2 */ + case OPCODE_INVOKESPECIAL: /* 0xb7 + u2 */ + case OPCODE_JSR: /* 0xa8 + s2 */ + case OPCODE_INVOKESTATIC: /* 0xb8 + u2 */ + case OPCODE_NEW: /* 0xbb + u2 */ + case OPCODE_ANEWARRAY: /* 0xbd + u2 */ + case OPCODE_CHECKCAST: /* 0xc0 + u2 */ + case OPCODE_INSTANCEOF: /* 0xc1 + u2 */ + case OPCODE_IFNULL: /* 0xc6 + s2 */ + case OPCODE_IFNONNULL: /* 0xc7 + s2 */ + assert( !is_wide ); + return location + 3; + + case OPCODE_BIPUSH: /* 0x10 + s1 */ + case OPCODE_LDC: /* 0x12 + u1 */ + case OPCODE_NEWARRAY: /* 0xbc + u1 */ + assert( !is_wide ); + return location + 2; + + default: + assert( !is_wide ); + assert( bytecode[location] < OPCODE_COUNT ); + assert( bytecode[location] != _OPCODE_UNDEFINED ); + return location + 1; + } + break; + } while( true ); + return 0; +} // jvmti_GetNextBytecodeLocation + +void +jvmti_dump_compiled_method(Method *method) +{ + unsigned location = 0; + unsigned bc_number = 0; + + do + { + OpenExeJpdaError res = EXE_ERROR_UNSUPPORTED; + NativeCodePtr native_location = NULL; + for (CodeChunkInfo* cci = method->get_first_JIT_specific_info(); cci; cci = cci->_next) + { + JIT *jit = cci->get_jit(); + res = jit->get_native_location_for_bc(method, + location, &native_location); + if (res == EXE_ERROR_NONE) + break; + } + assert(res == EXE_ERROR_NONE); + + TRACE2("jvmti.break.ss", "bytecode " << bc_number << ": " + << location << " = " << native_location); + + location = jvmti_GetNextBytecodeLocation(method, location); + bc_number++; + } + while(location < method->get_byte_code_size()); +} -- 1.3.3