diff --git a/vm/interpreter/src/interpreter_ti.cpp b/vm/interpreter/src/interpreter_ti.cpp index 505a0da..c36f6a5 100644 --- a/vm/interpreter/src/interpreter_ti.cpp +++ b/vm/interpreter/src/interpreter_ti.cpp @@ -356,6 +356,10 @@ Opcode_BREAKPOINT(StackFrame& frame) { jlocation l = frame.ip - (uint8*)m->get_byte_code_addr(); M2N_ALLOC_MACRO; uint8 b = (uint8) (POINTER_SIZE_INT) jvmti_process_interpreter_breakpoint_event((jmethodID)m, l); + if(b == OPCODE_COUNT) { + // breakpoint was remove by another thread, get original opcode + b = *(frame.ip); + } M2N_FREE_MACRO; return b; } diff --git a/vm/vmcore/include/jvmti_break_intf.h b/vm/vmcore/include/jvmti_break_intf.h index 23648db..a11341b 100755 --- a/vm/vmcore/include/jvmti_break_intf.h +++ b/vm/vmcore/include/jvmti_break_intf.h @@ -54,28 +54,36 @@ struct VMBreakPoint InstructionDisassembler* disasm; VMBreakPoint* next; NativeCodePtr addr; - jlocation location; jmethodID method; + jlocation location; jbyte saved_byte; - bool is_interp; - bool is_processed; }; // Breakpoint reference struct VMBreakPointRef { - VMBreakPoint* brpt; + VMBreakPoint* bp; void* data; VMBreakPointRef* next; }; +struct VMLocalBreak +{ + VMBreakPoint *bp; + VMBreakPoint *bp_next; + VMBreakInterface *intf; + VMLocalBreak* next; + unsigned priority; +}; + // Pointer to interface callback function -typedef bool (*BPInterfaceCallBack)(VMBreakInterface* intf, VMBreakPointRef* bp_ref); +typedef bool (*BPInterfaceCallBack)(TIEnv *env, VMBreakPoint* bp, void *data); +typedef bool (*BPInterfaceProcedure) (VMBreakPoint *bp); class VMBreakPoints { public: - VMBreakPoints() : m_break(NULL) + VMBreakPoints() : m_break(NULL), m_last(NULL), m_local(NULL) { for(unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { m_intf[index] = NULL; @@ -84,34 +92,36 @@ public: ~VMBreakPoints(); + // Class lock interface void lock() {m_lock._lock();} void unlock() {m_lock._unlock();} // Is used for LMAutoUnlock Lock_Manager* get_lock() {return &m_lock;} // Returns interface for breakpoint handling - VMBreakInterface* new_intf(BPInterfaceCallBack callback, + VMBreakInterface* new_intf(TIEnv *env, BPInterfaceCallBack callback, unsigned priority, bool is_interp); // Destroys interface and deletes all its breakpoints void release_intf(VMBreakInterface* intf); - // Checks breakpoint before inserting - bool check_insert_breakpoint(VMBreakPoint* bp); // Inserts breakpoint into global list and performs instrumentation - bool insert_breakpoint(VMBreakPoint* brpt); + bool insert_native_breakpoint(VMBreakPoint* bp); + bool insert_interpreter_breakpoint(VMBreakPoint* bp); // Removes breakpoint from global list and restores instrumented area - bool remove_breakpoint(VMBreakPoint* brpt); + bool remove_native_breakpoint(VMBreakPoint* bp); + bool remove_interpreter_breakpoint(VMBreakPoint* bp); - // Search operations + // Search breakpoints operations VMBreakPoint* find_breakpoint(jmethodID method, jlocation location); VMBreakPoint* find_breakpoint(NativeCodePtr addr); VMBreakPoint* find_other_breakpoint_with_same_addr(VMBreakPoint* bp); VMBreakPoint* find_next_breakpoint(VMBreakPoint* prev, NativeCodePtr addr); + VMBreakPoint* find_next_breakpoint(VMBreakPoint* prev, jmethodID method, + jlocation location); // Search breakpoints for given method - bool has_breakpoint(jmethodID method); - VMBreakPoint* find_first(jmethodID method); - VMBreakPoint* find_next(VMBreakPoint* prev, jmethodID method); + VMBreakPoint* find_method_breakpoint(jmethodID method); + VMBreakPoint* find_next_method_breakpoint(VMBreakPoint* prev, jmethodID method); // Checks if given breakpoint is set by other interfaces VMBreakPointRef* find_other_reference(VMBreakInterface* intf, @@ -119,31 +129,32 @@ public: VMBreakPointRef* find_other_reference(VMBreakInterface* intf, NativeCodePtr addr); VMBreakPointRef* find_other_reference(VMBreakInterface* intf, - VMBreakPoint* brpt); + VMBreakPoint* bp); + + // Interfaces iterator + VMBreakInterface* get_first_intf(unsigned priority) { return m_intf[priority]; } + VMBreakInterface* get_next_intf(VMBreakInterface *intf); // General callback functions void process_native_breakpoint(); jbyte process_interpreter_breakpoint(jmethodID method, jlocation location); -protected: - void clear_breakpoints_processed_flags(); - VMBreakPoint* get_none_processed_breakpoint(NativeCodePtr addr); - void set_breakpoint_processed( VMBreakPoint *bp, bool flag ) - { - bp->is_processed = flag; - } - bool breakpoint_is_processed( VMBreakPoint *bp ) - { - return bp->is_processed == true; - } +private: + // Checks breakpoint before inserting + inline bool check_insert_breakpoint(VMBreakPoint* bp); + void insert_breakpoint(VMBreakPoint* bp); + void remove_breakpoint(VMBreakPoint* bp); - void clear_intfs_processed_flags(); - VMBreakInterface* get_none_processed_intf(unsigned priority); + // Set/remove thread processing breakpoints interfaces + void set_thread_local_break(VMLocalBreak *local); + void remove_thread_local_break(VMLocalBreak *local); private: VMBreakInterface* m_intf[PRIORITY_NUMBER]; VMBreakPoint* m_break; - Lock_Manager m_lock; + VMBreakPoint* m_last; + VMLocalBreak* m_local; + Lock_Manager m_lock; }; class VMBreakInterface @@ -151,54 +162,60 @@ class VMBreakInterface friend class VMBreakPoints; public: - void lock() {VM_Global_State::loader_env->TI->vm_brpt->lock();} - void unlock() {VM_Global_State::loader_env->TI->vm_brpt->unlock();} - Lock_Manager* get_lock() - {return VM_Global_State::loader_env->TI->vm_brpt->get_lock();} - int get_priority() const { return m_priority; } // Iteration - VMBreakPointRef* get_first() { return m_list; } - VMBreakPointRef* get_next(VMBreakPointRef* prev) + VMBreakPointRef* get_reference() { return m_list; } + VMBreakPointRef* get_next_reference(VMBreakPointRef* ref) { - assert(prev); - return prev->next; + assert(ref); + return ref->next; } // Basic operations // 'data' must be allocated with JVMTI Allocate (or internal _allocate) // Users must not deallocate 'data', it will be deallocated by 'remove' - VMBreakPointRef* add(jmethodID method, jlocation location, void* data); + VMBreakPointRef* add_reference(jmethodID method, jlocation location, void* data); // To specify address explicitly - VMBreakPointRef* add(jmethodID method, jlocation location, + VMBreakPointRef* add_reference(jmethodID method, jlocation location, NativeCodePtr addr, void* data); - VMBreakPointRef* add(NativeCodePtr addr, void* data); + VMBreakPointRef* add_reference(NativeCodePtr addr, void* data); - void remove_all(); - bool remove(VMBreakPointRef* ref); + bool remove_reference(VMBreakPointRef* ref); + void remove_all_reference() + { + while (m_list) { + remove_reference(m_list); + } + } - VMBreakPointRef* find(jmethodID method, jlocation location); - VMBreakPointRef* find(NativeCodePtr addr); - VMBreakPointRef* find(VMBreakPoint* brpt); + VMBreakPointRef* find_reference(jmethodID method, jlocation location); + VMBreakPointRef* find_reference(NativeCodePtr addr); + VMBreakPointRef* find_reference(VMBreakPoint* bp); protected: - VMBreakInterface(BPInterfaceCallBack callback, unsigned priority, bool is_interp) - : m_list(NULL), m_callback(callback), m_priority(priority), - m_next(NULL), m_processed(false), m_is_interp(is_interp) {} - ~VMBreakInterface() { remove_all(); } + VMBreakInterface(TIEnv *env, + BPInterfaceCallBack callback, + unsigned priority, + bool is_interp); + ~VMBreakInterface() { remove_all_reference(); } + TIEnv* get_env() { return m_env; } - void set_processed(bool processed) { m_processed = processed; } - bool is_processed() const { return (m_processed == true); } +private: + inline VMBreakPointRef* add_reference_internal(VMBreakPoint *bp, void *data); + +protected: VMBreakInterface* m_next; private: - VMBreakPointRef* m_list; - BPInterfaceCallBack m_callback; - bool m_is_interp; - unsigned m_priority; - bool m_processed; + BPInterfaceCallBack breakpoint_event_callback; + BPInterfaceProcedure breakpoint_insert; + BPInterfaceProcedure breakpoint_remove; + VMBreakPointRef* m_list; + TIEnv *m_env; + unsigned m_priority; + Lock_Manager m_lock; }; // Callback function for native breakpoint processing diff --git a/vm/vmcore/include/jvmti_internal.h b/vm/vmcore/include/jvmti_internal.h index caef455..482ec23 100644 --- a/vm/vmcore/include/jvmti_internal.h +++ b/vm/vmcore/include/jvmti_internal.h @@ -74,19 +74,11 @@ struct jvmti_frame_pop_listener jvmti_frame_pop_listener *next; }; -/* - * Type which will be attached to each JVMTI breakpoint - */ -struct TIBrptData -{ - TIEnv *env; -}; - struct jvmti_StepLocation { struct Method* method; - unsigned location; NativeCodePtr native_location; + unsigned location; bool no_event; }; @@ -147,7 +139,7 @@ public: typedef struct Class Class; class VMBreakPoints; -struct VMBreakPointRef; +struct VMBreakPoint; /* * JVMTI state of the VM @@ -367,6 +359,6 @@ void jvmti_SingleStepLocation(VM_thread* unsigned location, jvmti_StepLocation **next_step, unsigned *count); // Callback function for JVMTI breakpoint processing -bool jvmti_process_breakpoint_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref); +bool jvmti_process_breakpoint_event(TIEnv *env, VMBreakPoint* bp, void* data); #endif /* _JVMTI_INTERNAL_H_ */ diff --git a/vm/vmcore/src/exception/exceptions_jit.cpp b/vm/vmcore/src/exception/exceptions_jit.cpp index 5c1fca5..15344ca 100644 --- a/vm/vmcore/src/exception/exceptions_jit.cpp +++ b/vm/vmcore/src/exception/exceptions_jit.cpp @@ -278,7 +278,7 @@ #endif // VM_STATS jit->get_bc_location_for_native(method, ip, &bc); assert(EXE_ERROR_NONE == result); - jvmti_StepLocation method_start = {(Method *)method, bc, ip}; + jvmti_StepLocation method_start = {(Method *)method, ip, bc, false}; jvmti_set_single_step_breakpoints(ti, vm_thread, &method_start, 1); diff --git a/vm/vmcore/src/jvmti/jvmti.cpp b/vm/vmcore/src/jvmti/jvmti.cpp index 803f091..4f79d37 100644 --- a/vm/vmcore/src/jvmti/jvmti.cpp +++ b/vm/vmcore/src/jvmti/jvmti.cpp @@ -266,7 +266,8 @@ jint JNICALL create_jvmti_environment(Ja // Acquire interface for breakpoint handling newenv->brpt_intf = - vm->vm_env->TI->vm_brpt->new_intf(jvmti_process_breakpoint_event, + vm->vm_env->TI->vm_brpt->new_intf(newenv, + jvmti_process_breakpoint_event, PRIORITY_SIMPLE_BREAKPOINT, interpreter_enabled()); diff --git a/vm/vmcore/src/jvmti/jvmti_break.cpp b/vm/vmcore/src/jvmti/jvmti_break.cpp index e69fee0..d8d47f4 100644 --- a/vm/vmcore/src/jvmti/jvmti_break.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break.cpp @@ -37,16 +37,17 @@ #include "open/hythread_ext.h" // Callback function for JVMTI breakpoint processing -bool jvmti_process_breakpoint_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref) +bool jvmti_process_breakpoint_event(TIEnv *env, VMBreakPoint* bp, void* UNREF data) { - VMBreakPoint* bp = bp_ref->brpt; assert(bp); TRACE2("jvmti.break", "Process breakpoint: " - << class_get_name(method_get_class((Method*)bp->method)) << "." - << method_get_name((Method*)bp->method) - << method_get_descriptor((Method*)bp->method) - << " :" << bp->location << " :" << bp->addr); + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr ); DebugUtilsTI *ti = VM_Global_State::loader_env->TI; if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE) @@ -54,8 +55,7 @@ bool jvmti_process_breakpoint_event(VMBr jlocation location = bp->location; jmethodID method = bp->method; - TIBrptData* data = (TIBrptData*)bp_ref->data; - TIEnv *env = data->env; + NativeCodePtr addr = bp->addr; hythread_t h_thread = hythread_self(); jthread j_thread = jthread_get_java_thread(h_thread); @@ -76,17 +76,15 @@ bool jvmti_process_breakpoint_event(VMBr << class_get_name(method_get_class((Method*)method)) << "." << method_get_name((Method*)method) << method_get_descriptor((Method*)method) - << " :" << location); + << " :" << location << " :" << addr); - intf->unlock(); func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - intf->lock(); TRACE2("jvmti.break", "Finished global breakpoint callback: " << class_get_name(method_get_class((Method*)method)) << "." << method_get_name((Method*)method) << method_get_descriptor((Method*)method) - << " :" << location); + << " :" << location << " :" << addr); } else { @@ -104,17 +102,15 @@ bool jvmti_process_breakpoint_event(VMBr << class_get_name(method_get_class((Method*)method)) << "." << method_get_name((Method*)method) << method_get_descriptor((Method*)method) - << " :" << location); + << " :" << location << " :" << addr); - intf->unlock(); func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - intf->lock(); TRACE2("jvmti.break", "Finished local breakpoint callback: " << class_get_name(method_get_class((Method*)method)) << "." << method_get_name((Method*)method) << method_get_descriptor((Method*)method) - << " :" << location); + << " :" << location << " :" << addr); } } } @@ -190,25 +186,16 @@ #endif TIEnv *p_env = (TIEnv *)env; VMBreakInterface* brpt_intf = p_env->brpt_intf; - LMAutoUnlock lock(brpt_intf->get_lock()); + VMBreakPoints *vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + LMAutoUnlock lock(vm_breaks->get_lock()); - VMBreakPointRef* bp = brpt_intf->find(method, location); + VMBreakPointRef* bp = brpt_intf->find_reference(method, location); if (NULL != bp) return JVMTI_ERROR_DUPLICATE; - TIBrptData* data; - errorCode = _allocate(sizeof(TIBrptData), (unsigned char**)&data); - if (JVMTI_ERROR_NONE != errorCode) - return errorCode; - - data->env = p_env; - - if (!brpt_intf->add(method, location, data)) - { - _deallocate((unsigned char*)data); + if (!brpt_intf->add_reference(method, location, NULL)) return JVMTI_ERROR_INTERNAL; - } TRACE2("jvmti.break", "SetBreakpoint is successfull"); return JVMTI_ERROR_NONE; @@ -278,14 +265,15 @@ #endif TIEnv *p_env = (TIEnv *)env; VMBreakInterface* brpt_intf = p_env->brpt_intf; - LMAutoUnlock lock(brpt_intf->get_lock()); + VMBreakPoints *vm_breaks = VM_Global_State::loader_env->TI->vm_brpt; + LMAutoUnlock lock(vm_breaks->get_lock()); - VMBreakPointRef* bp = brpt_intf->find(method, location); + VMBreakPointRef* bp_ref = brpt_intf->find_reference(method, location); - if (NULL == bp) + if (NULL == bp_ref) return JVMTI_ERROR_NOT_FOUND; - if (!brpt_intf->remove(bp)) + if (!brpt_intf->remove_reference(bp_ref)) return JVMTI_ERROR_INTERNAL; TRACE2("jvmti.break", "ClearBreakpoint is successfull"); diff --git a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp index b16fe93..b401291 100755 --- a/vm/vmcore/src/jvmti/jvmti_break_intf.cpp +++ b/vm/vmcore/src/jvmti/jvmti_break_intf.cpp @@ -25,20 +25,21 @@ #include "cxxlog.h" #include "environment.h" #include "encoder.h" +#include "interpreter.h" #include "interpreter_exports.h" #include "jit_intf_cpp.h" #include "method_lookup.h" #include "exceptions.h" #include "m2n.h" #include "stack_iterator.h" - +#include "open/bytecodes.h" #include "jvmti_break_intf.h" // Forvard declarations static ConditionCode get_condition_code(InstructionDisassembler::CondJumpType jump_type); -static bool set_jit_mode_breakpoint(VMBreakPoints* vm_brpt, VMBreakPoint* bp); +static bool set_jit_mode_breakpoint(VMBreakPoint* bp); static bool set_native_breakpoint(VMBreakPoint* bp); static bool clear_native_breakpoint(VMBreakPoint* bp); @@ -60,18 +61,39 @@ VMBreakPoints::~VMBreakPoints() } VMBreakInterface* -VMBreakPoints::new_intf(BPInterfaceCallBack callback, +VMBreakPoints::new_intf(TIEnv *env, + BPInterfaceCallBack callback, unsigned priority, bool is_interp) { assert(callback); assert(priority < PRIORITY_NUMBER); - VMBreakInterface* intf = new VMBreakInterface(callback, priority, is_interp); + VMBreakInterface* intf = new VMBreakInterface(env, callback, priority, is_interp); assert(intf); lock(); - intf->m_next = m_intf[priority]; - m_intf[priority] = intf; + + TRACE2("jvmti.break", "Create breakpoint interface: " << intf ); + + // add interface to the end of list + if( NULL == m_intf[priority] ) { + m_intf[priority] = intf; + } else { + VMBreakInterface *last = m_intf[priority]; + for( ; last->m_next; last = last->m_next ) + ; + last->m_next = intf; + } + + // correct thread processing breakpoints + for(VMLocalBreak *local = m_local; local; local = local->next) { + if( local->priority == priority && NULL == local->intf ) { + TRACE2("jvmti.break", "Set local thread interface: " + << local << ", intf: " << intf ); + local->intf = intf; + } + } + unlock(); return intf; @@ -84,8 +106,21 @@ VMBreakPoints::release_intf(VMBreakInter assert(intf->get_priority() < PRIORITY_NUMBER); LMAutoUnlock lock(get_lock()); + TRACE2("jvmti.break", "Release breakpoint interface: " << intf ); + + // correct thread processing breakpoints + for(VMLocalBreak *local = m_local; local; local = local->next) { + if( local->intf == intf ) { + TRACE2("jvmti.break", "Set local thread interface: " + << local << ", intf: " << intf->m_next ); + local->intf = intf->m_next; + } + } + + // release interface for (VMBreakInterface** cur_ptr = &m_intf[intf->get_priority()]; - *cur_ptr; cur_ptr = &((*cur_ptr)->m_next)) + *cur_ptr; + cur_ptr = &((*cur_ptr)->m_next)) { if (*cur_ptr == intf) { @@ -98,6 +133,12 @@ VMBreakPoints::release_intf(VMBreakInter DIE2("jvmti.break", "VMBreakPoints::release_intf: try to release unknown interface"); } +VMBreakInterface* +VMBreakPoints::get_next_intf(VMBreakInterface *intf) +{ + return intf->m_next; +} + inline bool VMBreakPoints::check_insert_breakpoint(VMBreakPoint* bp) { @@ -121,7 +162,7 @@ #ifndef NDEBUG ? class_get_name(method_get_class((Method*)another->method)): "(nil)") << "." << (another->method ? method_get_name((Method*)another->method) : "(nil)") - << (another->method ? method_get_descriptor((Method*)another->method) : "(nil)") + << (another->method ? method_get_descriptor((Method*)another->method) : "") << " :" << another->location << " :" << another->addr); if( bp->addr == another->addr) { @@ -141,7 +182,7 @@ #ifndef NDEBUG ? class_get_name(method_get_class((Method*)another->method)) :"(nil)") << "." << (another->method ? method_get_name((Method*)another->method) :"(nil)") - << (another->method ? method_get_descriptor((Method*)another->method) :"(nil)") + << (another->method ? method_get_descriptor((Method*)another->method) :"") << " :" << another->location << " :" << another->addr); if(another->method) { @@ -154,100 +195,190 @@ #endif // !NDEBUG return true; } -bool -VMBreakPoints::insert_breakpoint(VMBreakPoint* brpt) +inline void +VMBreakPoints::insert_breakpoint(VMBreakPoint* bp) { - check_insert_breakpoint(brpt); - if (brpt->is_interp) - { - assert(interpreter_enabled()); - brpt->saved_byte = (POINTER_SIZE_INT) - interpreter.interpreter_ti_set_breakpoint(brpt->method, brpt->location); + TRACE2("jvmti.break", "Insert breakpoint: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr); + + // add breakpoint to the end of list + if(m_last) { + m_last->next = bp; + } else { + m_break = bp; } - else - { - if (brpt->method != NULL) - { // JIT breakpoint - Method *m = (Method *)brpt->method; + m_last = bp; + bp->next = NULL; + + // correct thread processing breakpoints + for(VMLocalBreak *local = m_local; local; local = local->next) { + if( !local->bp_next ) { + TRACE2("jvmti.break", "Set local thread next breakpoint: " + << local << ", next: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr); + local->bp_next = bp; + } + } + return; +} - if (m->get_state() == Method::ST_Compiled) - { - if (!set_jit_mode_breakpoint(this, brpt)) - return false; - } - else - { - assert(brpt->addr == NULL); - TRACE2("jvmti.break.intf", "Skipping setting breakpoing in method " - << class_get_name(method_get_class(m)) << "." - << method_get_name(m) - << method_get_descriptor(m) - << " because it is not compiled yet"); - m->insert_pending_breakpoint(); - } +bool +VMBreakPoints::insert_native_breakpoint(VMBreakPoint* bp) +{ + LMAutoUnlock lock(get_lock()); + + assert(!interpreter_enabled()); + bool UNREF check = check_insert_breakpoint(bp); + assert(check); + if (bp->method != NULL) + { // JIT breakpoint + Method *m = (Method *)bp->method; + + if (m->get_state() == Method::ST_Compiled) + { + if (!set_jit_mode_breakpoint(bp)) + return false; } else { - if (!set_native_breakpoint(brpt)) - return false; + assert(bp->addr == NULL); + TRACE2("jvmti.break.intf", "Skipping setting breakpoing in method " + << class_get_name(method_get_class(m)) << "." + << method_get_name(m) + << method_get_descriptor(m) + << " because it is not compiled yet"); + m->insert_pending_breakpoint(); } } - TRACE2("jvmti.break.intf", "Insert breakpoint: " - << class_get_name(method_get_class((Method*)brpt->method)) << "." - << method_get_name((Method*)brpt->method) - << method_get_descriptor((Method*)brpt->method) - << " :" << brpt->location << " :" << brpt->addr); - - brpt->next = m_break; - m_break = brpt; - + else + { + if (!set_native_breakpoint(bp)) + return false; + } + insert_breakpoint(bp); return true; } bool -VMBreakPoints::remove_breakpoint(VMBreakPoint* brpt) +VMBreakPoints::insert_interpreter_breakpoint(VMBreakPoint* bp) { - assert(brpt); - assert(!brpt->method || find_breakpoint(brpt->method, brpt->location)); - assert(brpt->method || find_breakpoint(brpt->addr)); + LMAutoUnlock lock(get_lock()); + assert(interpreter_enabled()); + bool UNREF check = check_insert_breakpoint(bp); + assert(check); + bp->saved_byte = (POINTER_SIZE_INT) + interpreter.interpreter_ti_set_breakpoint(bp->method, bp->location); + + insert_breakpoint(bp); + return true; +} + +inline void +VMBreakPoints::remove_breakpoint(VMBreakPoint* bp) +{ TRACE2("jvmti.break.intf", "Remove breakpoint: " - << class_get_name(method_get_class((Method*)brpt->method)) << "." - << method_get_name((Method*)brpt->method) - << method_get_descriptor((Method*)brpt->method) - << " :" << brpt->location << " :" << brpt->addr); + << (bp->method ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)" ) + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)" ) + << (bp->method ? method_get_descriptor((Method*)bp->method) : "" ) + << " :" << bp->location << " :" << bp->addr); - for (VMBreakPoint** cur_ptr = &m_break; - *cur_ptr; cur_ptr = &(*cur_ptr)->next) + // remove breakpoint from list + VMBreakPoint *last = NULL; + for( VMBreakPoint *index = m_break; + index; + last = index, index = index->next ) { - if (*cur_ptr == brpt) - { - *cur_ptr = (*cur_ptr)->next; + if(index == bp) { + if(m_last == bp) { + m_last = last; + } + if(last) { + last->next = index->next; + } else { + m_break = index->next; + } break; } } - if (brpt->is_interp) + // correct thread processing breakpoints + for(VMLocalBreak *local = m_local; local; local = local->next) { + if( local->bp == bp ) { + // processed breakpoint was removed + TRACE2("jvmti.break", "Remove local thread breakpoint: " + << local << ", bp: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr); + + local->bp = NULL; + } else if( local->bp_next == bp ) { + // set new next breakpoint + TRACE2("jvmti.break", "Set local thread next breakpoint: " + << local << ", next: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr); + local->bp_next = bp->next; + } + } + return; +} + +bool +VMBreakPoints::remove_native_breakpoint(VMBreakPoint* bp) +{ + assert(bp); + assert(!bp->method || find_breakpoint(bp->method, bp->location)); + assert(bp->method || find_breakpoint(bp->addr)); + assert(!interpreter_enabled()); + + LMAutoUnlock lock(get_lock()); + remove_breakpoint(bp); + if (bp->addr) { - assert(interpreter_enabled()); - interpreter.interpreter_ti_clear_breakpoint(brpt->method, - brpt->location, brpt->saved_byte); + assert(!bp->method || (((Method*)bp->method)->get_state() == Method::ST_Compiled)); + return clear_native_breakpoint(bp); } else { - if (brpt->addr) - { - assert(!brpt->method || (((Method*)brpt->method)->get_state() == Method::ST_Compiled)); - return clear_native_breakpoint(brpt); - } - else - { - assert(brpt->method && (((Method*)brpt->method)->get_state() != Method::ST_Compiled)); - Method *m = (Method *)brpt->method; - m->remove_pending_breakpoint(); - } + assert(bp->method && (((Method*)bp->method)->get_state() != Method::ST_Compiled)); + Method *m = (Method *)bp->method; + m->remove_pending_breakpoint(); } + return true; +} +bool +VMBreakPoints::remove_interpreter_breakpoint(VMBreakPoint* bp) +{ + assert(bp); + assert(bp->method); + assert(find_breakpoint(bp->method, bp->location)); + assert(interpreter_enabled()); + + LMAutoUnlock lock(get_lock()); + remove_breakpoint(bp); + interpreter.interpreter_ti_clear_breakpoint(bp->method, + bp->location, bp->saved_byte); return true; } @@ -307,14 +438,25 @@ VMBreakPoints::find_next_breakpoint(VMBr return NULL; } -bool -VMBreakPoints::has_breakpoint(jmethodID method) +VMBreakPoint* +VMBreakPoints::find_next_breakpoint(VMBreakPoint* prev, + jmethodID method, + jlocation location) { - return (find_first(method) != NULL); + assert(prev); + assert(method); + + for (VMBreakPoint* bp = prev->next; bp; bp = bp->next) { + if (bp->method == method && bp->location == location) { + return bp; + } + } + + return NULL; } VMBreakPoint* -VMBreakPoints::find_first(jmethodID method) +VMBreakPoints::find_method_breakpoint(jmethodID method) { assert(method); @@ -329,7 +471,7 @@ VMBreakPoints::find_first(jmethodID meth } VMBreakPoint* -VMBreakPoints::find_next(VMBreakPoint* prev, jmethodID method) +VMBreakPoints::find_next_method_breakpoint(VMBreakPoint* prev, jmethodID method) { assert(prev); @@ -354,7 +496,7 @@ VMBreakPoints::find_other_reference(VMBr if (cur == intf) continue; - VMBreakPointRef* ref = cur->find(method, location); + VMBreakPointRef* ref = cur->find_reference(method, location); if (ref) return ref; @@ -375,7 +517,7 @@ VMBreakPoints::find_other_reference(VMBr if (cur == intf) continue; - VMBreakPointRef* ref = cur->find(addr); + VMBreakPointRef* ref = cur->find_reference(addr); if (ref) return ref; @@ -396,7 +538,7 @@ VMBreakPoints::find_other_reference(VMBr if (cur == intf) continue; - VMBreakPointRef* ref = cur->find(brpt); + VMBreakPointRef* ref = cur->find_reference(brpt); if (ref) return ref; @@ -407,6 +549,35 @@ VMBreakPoints::find_other_reference(VMBr } void +VMBreakPoints::set_thread_local_break(VMLocalBreak *local) +{ + local->next = m_local; + m_local = local; + TRACE2( "jvmti.break", "Set local thread structure: " << local); +} + +void +VMBreakPoints::remove_thread_local_break(VMLocalBreak *local) +{ + TRACE2( "jvmti.break", "Remove local thread structure: " << local); + VMLocalBreak *last = NULL; + for( VMLocalBreak *index = m_local; + index; + last = index, index = index->next ) + { + if(index == local) { + if(last) { + last->next = index->next; + } else { + m_local = index->next; + } + return; + } + } + assert(false); +} + +void VMBreakPoints::process_native_breakpoint() { // When we get here we know already that breakpoint occurred in JITted code, @@ -420,20 +591,32 @@ #if _IA32_ && PLATFORM_POSIX && INSTRUME #endif //_IA32_ && PLATFORM_POSIX && INSTRUMENTATION_BYTE == INSTRUMENTATION_BYTE_INT3 NativeCodePtr addr = (NativeCodePtr)regs.get_ip(); - TRACE2("jvmti.break.intf", "Native breakpoint occured: " << addr); + TRACE2("jvmti.break", "Native breakpoint occured: " << addr); + lock(); VMBreakPoint* bp = find_breakpoint(addr); - assert(bp); + if (NULL == bp) { + // breakpoint could be deleted by another thread + unlock(); + return; + } + assert(bp->addr == addr); + TRACE2("jvmti.break", "Process native breakpoint: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)") + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr); bool push_frame = (vm_identify_eip(addr) == VM_TYPE_JAVA); M2nFrame* m2nf; - if (push_frame) - { + if (push_frame) { m2nf = m2n_push_suspended_frame(®s); - } - else + } else { m2nf = m2n_get_last_frame(); + } jbyte *instruction_buffer; BEGIN_RAISE_AREA; @@ -450,37 +633,75 @@ #endif //_IA32_ && PLATFORM_POSIX && INS for (unsigned priority = 0; priority < PRIORITY_NUMBER; priority++) { - while( bp = get_none_processed_breakpoint(addr) ) { - set_breakpoint_processed(bp, true); + bp = find_breakpoint(addr); + assert(!bp || bp->addr == addr); + VMLocalBreak local; + local.priority = priority; + while( bp ) + { + assert(bp->addr == addr); + // copy breakpoint to local thread variable + local.bp = bp; + local.bp_next = find_next_breakpoint(bp, addr); - VMBreakInterface* intf; - while( intf = get_none_processed_intf(priority) ) + VMBreakInterface *intf = get_first_intf(priority); + while( intf ) { - intf->set_processed(true); - VMBreakPointRef* ref = intf->find(bp); + VMBreakPointRef* ref = intf->find_reference(bp); + assert(!ref || ref->bp->addr == addr); - if (ref && bp->addr != addr) - break; // It's another breakpoint now... - - if (ref && intf->m_callback != NULL) + if (ref && intf->breakpoint_event_callback != NULL) { - TRACE2("jvmti.break.intf", + local.intf = intf->m_next; + VMBreakPoint local_bp = *bp; + void *data = ref->data; + + Method *method = (Method*)bp->method; + jlocation location = bp->location; + NativeCodePtr addr = bp->addr; + TRACE2("jvmti.break", "Calling native breakpoint callback function: " - << class_get_name(method_get_class((Method*)bp->method)) << "." - << method_get_name((Method*)bp->method) - << method_get_descriptor((Method*)bp->method) - << " :" << bp->location << " :" << bp->addr ); - - intf->m_callback(intf, ref); - - TRACE2("jvmti.break.intf", - "Finished native breakpoint callback function: " << addr ); + << (method + ? class_get_name(method_get_class(method)) : "(nil)") + << "." + << (method ? method_get_name(method) : "(nil)") + << (method ? method_get_descriptor(method) : "") + << " :" << location << " :" << addr); + + set_thread_local_break(&local); + unlock(); + + // call event breakpoint callback + intf->breakpoint_event_callback(intf->get_env(), &local_bp, data); + + lock(); + remove_thread_local_break(&local); + + TRACE2("jvmti.break", + "Finished native breakpoint callback function: " + << (method + ? class_get_name(method_get_class(method)) : "(nil)") + << "." + << (method ? method_get_name(method) : "(nil)") + << (method ? method_get_descriptor(method) : "") + << " :" << location << " :" << addr); + + if( !local.bp ) { + // breakpoint was removed, no need report it anymore + break; + } + intf = local.intf; + } else { + intf = intf->m_next; } } - clear_intfs_processed_flags(); + bp = local.bp_next; + if( bp && bp->addr != addr ) { + bp = find_next_breakpoint(bp, addr); + } } - clear_breakpoints_processed_flags(); } + unlock(); // Now we need to return back to normal code execution, it is // necessary to execute the original instruction The idea is to @@ -581,8 +802,6 @@ #endif //_IA32_ && PLATFORM_POSIX && INS } } - unlock(); - END_RAISE_AREA; // This function does not return. It restores register context and @@ -615,163 +834,208 @@ VMBreakPoints::process_interpreter_break lock(); VMBreakPoint* bp = find_breakpoint(method, location); - assert(bp); + if(NULL == bp) { + // breakpoint could be deleted by another thread + unlock(); + return (jbyte)OPCODE_COUNT; + } + assert(bp->method == method); + assert(bp->location == location); + TRACE2("jvmti.break", "Process interpreter breakpoint: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); jbyte orig_byte = bp->saved_byte; for (unsigned priority = 0; priority < PRIORITY_NUMBER; priority++) { - VMBreakInterface* intf; - - while (intf = get_none_processed_intf(priority) ) + bp = find_breakpoint(method, location);; + assert(bp->method == method); + assert(bp->location == location); + VMLocalBreak local; + local.priority = priority; + while( bp ) { - intf->set_processed(true); - VMBreakPointRef* ref = intf->find(bp); + assert(bp->method == method); + assert(bp->location == location); + // copy breakpoint to local thread variable + local.bp = bp; + local.bp_next = find_next_breakpoint(bp, method, location); + + VMBreakInterface *intf = get_first_intf(priority); + while( intf ) + { + VMBreakPointRef* ref = intf->find_reference(bp); + assert(!ref || ref->bp->method == method); + assert(!ref || ref->bp->location == location); - if (ref && - ( bp->method != method || - bp->location != location )) - break; // It's another breakpoint now... + if (ref && intf->breakpoint_event_callback != NULL) + { + local.intf = intf->m_next; + VMBreakPoint local_bp = *bp; + void *data = ref->data; - if (ref && intf->m_callback != NULL) - { - JNIEnv *jni_env = (JNIEnv *)jni_native_intf; - TRACE2("jvmti.break.intf", - "Calling interpreter breakpoint callback function: " - << class_get_name(method_get_class((Method*)method)) << "." - << method_get_name((Method*)method) - << method_get_descriptor((Method*)method) - << " :" << location ); - - intf->m_callback(intf, ref); - - TRACE2("jvmti.break.intf", - "Finished interpreter breakpoint callback function: " - << class_get_name(method_get_class((Method*)method)) << "." - << method_get_name((Method*)method) - << method_get_descriptor((Method*)method) - << " :" << location ); + TRACE2("jvmti.break.intf", + "Calling interpreter breakpoint callback function: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); + + set_thread_local_break(&local); + unlock(); + + // call event breakpoint callback + intf->breakpoint_event_callback(intf->get_env(), &local_bp, data); + + lock(); + remove_thread_local_break(&local); + + TRACE2("jvmti.break", + "Finished interpreter breakpoint callback function: " + << class_get_name(method_get_class((Method*)method)) << "." + << method_get_name((Method*)method) + << method_get_descriptor((Method*)method) + << " :" << location ); + + if( !local.bp ) { + // breakpoint was removed, no need report it anymore + break; + } + intf = local.intf; + } else { + intf = intf->m_next; + } + } + bp = local.bp_next; + if( bp && !(bp->method == method && bp->location == location) ) { + bp = find_next_breakpoint(bp, method, location); } } } - - clear_intfs_processed_flags(); unlock(); return orig_byte; } -void -VMBreakPoints::clear_breakpoints_processed_flags() -{ - LMAutoUnlock lock(get_lock()); +////////////////////////////////////////////////////////////////////////////// +// VMBreakInterface implementation - for(VMBreakPoint *bp = m_break; bp; bp = bp->next ) { - set_breakpoint_processed( bp, false ); - } +static bool insert_native_breakpoint(VMBreakPoint *bp) +{ + return VM_Global_State::loader_env-> + TI->vm_brpt->insert_native_breakpoint(bp); } -VMBreakPoint* -VMBreakPoints::get_none_processed_breakpoint(NativeCodePtr addr) +static bool insert_interpreter_breakpoint(VMBreakPoint *bp) { - LMAutoUnlock lock(get_lock()); - - for(VMBreakPoint *bp = find_breakpoint(addr); - bp; - bp = find_next_breakpoint(bp, addr) ) - { - if(!breakpoint_is_processed(bp)) { - return bp; - } - } + return VM_Global_State::loader_env-> + TI->vm_brpt->insert_interpreter_breakpoint(bp); +} - return NULL; +static bool remove_native_breakpoint(VMBreakPoint *bp) +{ + return VM_Global_State::loader_env-> + TI->vm_brpt->remove_native_breakpoint(bp); } -void -VMBreakPoints::clear_intfs_processed_flags() +static bool remove_interpreter_breakpoint(VMBreakPoint *bp) { - LMAutoUnlock lock(get_lock()); + return VM_Global_State::loader_env-> + TI->vm_brpt->remove_interpreter_breakpoint(bp); +} - for(unsigned index = 0; index < PRIORITY_NUMBER; index++ ) { - for (VMBreakInterface* intf = m_intf[index]; intf; intf = intf->m_next) { - intf->set_processed(false); - } +VMBreakInterface::VMBreakInterface(TIEnv *env, + BPInterfaceCallBack callback, + unsigned priority, + bool is_interp) + : m_next(NULL), breakpoint_event_callback(callback), m_list(NULL), + m_env(env), m_priority(priority) +{ + if(is_interp) { + breakpoint_insert = &insert_interpreter_breakpoint; + breakpoint_remove = &remove_interpreter_breakpoint; + } else { + breakpoint_insert = &insert_native_breakpoint; + breakpoint_remove = &remove_native_breakpoint; } } -VMBreakInterface* -VMBreakPoints::get_none_processed_intf(unsigned priority) +inline VMBreakPointRef* +VMBreakInterface::add_reference_internal(VMBreakPoint *bp, void *data) { - LMAutoUnlock lock(get_lock()); - - for (VMBreakInterface* intf = m_intf[priority]; intf; intf = intf->m_next) { - if (!intf->is_processed()) { - assert(intf->get_priority() == priority); - return intf; - } - } + VMBreakPointRef* bp_ref = + (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); + assert(bp_ref); - return NULL; -} + bp_ref->bp = bp; + bp_ref->data = data; + bp_ref->next = m_list; + m_list = bp_ref; + TRACE2("jvmti.break.intf", "Added ref on breakpoint: " + << (bp->method + ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)" ) + << "." + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)") + << (bp->method ? method_get_descriptor((Method*)bp->method) : "") + << " :" << bp->location << " :" << bp->addr << ", data: " << data); -////////////////////////////////////////////////////////////////////////////// -// VMBreakInterface implementation + return bp_ref; +} -VMBreakPointRef* VMBreakInterface::add(jmethodID method, jlocation location, void* data) +VMBreakPointRef* +VMBreakInterface::add_reference(jmethodID method, jlocation location, void* data) { assert(method); - assert(!this->find(method, location)); VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VMBreakPoint* brpt = vm_brpt->find_breakpoint(method, location); + LMAutoUnlock lock(vm_brpt->get_lock()); + + // find existing reference + VMBreakPointRef *ref = find_reference(method, location); + if( ref && ref->data == data ) { + return ref; + } + VMBreakPoint* brpt = vm_brpt->find_breakpoint(method, location); if (!brpt) { brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); - brpt->is_interp = m_is_interp; brpt->addr = NULL; brpt->method = method; brpt->location = location; brpt->saved_byte = 0; brpt->disasm = NULL; - brpt->is_processed = false; // Insert breakpoint, possibly to the same native address - if (!vm_brpt->insert_breakpoint(brpt)) + if (!breakpoint_insert(brpt)) { STD_FREE(brpt); return false; } } - - VMBreakPointRef* brpt_ref = - (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); - assert(brpt_ref); - - brpt_ref->brpt = brpt; - brpt_ref->data = data; - brpt_ref->next = m_list; - m_list = brpt_ref; - - TRACE2("jvmti.break.intf", "Added ref on breakpoint: " - << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." - << method_get_name((Method*)brpt_ref->brpt->method) - << method_get_descriptor((Method*)brpt_ref->brpt->method) - << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); - - return brpt_ref; + return add_reference_internal( brpt, data ); } -VMBreakPointRef* VMBreakInterface::add(jmethodID method, jlocation location, - NativeCodePtr addr, void* data) +VMBreakPointRef* +VMBreakInterface::add_reference(jmethodID method, jlocation location, + NativeCodePtr addr, void* data) { assert(method); - assert(!this->find(method, location)); VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + LMAutoUnlock lock(vm_brpt->get_lock()); + + // find existing reference + VMBreakPointRef *ref = find_reference(method, location); + if( ref && (!addr || addr == ref->bp->addr) && data == ref->data ) { + return ref; + } + VMBreakPoint* brpt = vm_brpt->find_breakpoint(method, location); // If breakpoint with the same method location is not found or @@ -783,104 +1047,81 @@ VMBreakPointRef* VMBreakInterface::add(j brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); - brpt->is_interp = m_is_interp; brpt->addr = addr; brpt->method = method; brpt->location = location; brpt->saved_byte = 0; brpt->disasm = NULL; - brpt->is_processed = false; - if (!vm_brpt->insert_breakpoint(brpt)) + if (!breakpoint_insert(brpt)) { STD_FREE(brpt); return false; } } - - VMBreakPointRef* brpt_ref = - (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); - assert(brpt_ref); - - brpt_ref->brpt = brpt; - brpt_ref->data = data; - brpt_ref->next = m_list; - m_list = brpt_ref; - - TRACE2("jvmti.break.intf", "Added ref on breakpoint: " - << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." - << method_get_name((Method*)brpt_ref->brpt->method) - << method_get_descriptor((Method*)brpt_ref->brpt->method) - << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); - - return brpt_ref; + return add_reference_internal( brpt, data ); } -VMBreakPointRef* VMBreakInterface::add(NativeCodePtr addr, void* data) +VMBreakPointRef* +VMBreakInterface::add_reference(NativeCodePtr addr, void* data) { assert(addr); - assert(!this->m_is_interp); - assert(!this->find(addr)); + assert(!interpreter_enabled()); VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; - VMBreakPoint* brpt = vm_brpt->find_breakpoint(addr); + LMAutoUnlock lock(vm_brpt->get_lock()); + // find existing reference + VMBreakPointRef *ref = find_reference(addr); + if( ref && ref->data == data ) { + return ref; + } + + VMBreakPoint* brpt = vm_brpt->find_breakpoint(addr); if (!brpt) { brpt = (VMBreakPoint*)STD_MALLOC(sizeof(VMBreakPoint)); assert(brpt); - brpt->is_interp = m_is_interp; // false brpt->addr = addr; brpt->method = NULL; brpt->location = 0; brpt->saved_byte = 0; brpt->disasm = NULL; - brpt->is_processed = false; // Insert breakpoint, possibly duplicating breakpoint with method != NULL - if (!vm_brpt->insert_breakpoint(brpt)) + if (!breakpoint_insert(brpt)) { STD_FREE(brpt); return false; } } - - VMBreakPointRef* brpt_ref = - (VMBreakPointRef*)STD_MALLOC(sizeof(VMBreakPointRef)); - assert(brpt_ref); - - brpt_ref->brpt = brpt; - brpt_ref->data = data; - brpt_ref->next = m_list; - m_list = brpt_ref; - - TRACE2("jvmti.break.intf", "Added ref on breakpoint: " - << class_get_name(method_get_class((Method*)brpt_ref->brpt->method)) << "." - << method_get_name((Method*)brpt_ref->brpt->method) - << method_get_descriptor((Method*)brpt_ref->brpt->method) - << " :" << brpt_ref->brpt->location << " :" << brpt_ref->brpt->addr); - - return brpt_ref; + return add_reference_internal( brpt, data ); } -bool VMBreakInterface::remove(VMBreakPointRef* ref) +bool +VMBreakInterface::remove_reference(VMBreakPointRef* bp_ref) { - assert(ref); - - TRACE2("jvmti.break.intf", "Remove ref on breakpoint: " - << class_get_name(method_get_class((Method*)ref->brpt->method)) << "." - << method_get_name((Method*)ref->brpt->method) - << method_get_descriptor((Method*)ref->brpt->method) - << " :" << ref->brpt->location << " :" << ref->brpt->addr); + assert(bp_ref); VMBreakPoints* vm_brpt = VM_Global_State::loader_env->TI->vm_brpt; + LMAutoUnlock lock(vm_brpt->get_lock()); + + TRACE2("jvmti.break.intf", "Remove reference on breakpoint: " + << (bp_ref->bp->method + ? class_get_name(method_get_class((Method*)bp_ref->bp->method)) : "(nil)") + << "." + << (bp_ref->bp->method ? method_get_name((Method*)bp_ref->bp->method) : "(nil)") + << (bp_ref->bp->method ? method_get_descriptor((Method*)bp_ref->bp->method) : "") + << " :" << bp_ref->bp->location << " :" << bp_ref->bp->addr + << ", data: " << bp_ref->data ); + VMBreakPointRef* found = NULL; for (VMBreakPointRef** cur_ptr = &m_list; *cur_ptr; cur_ptr = &(*cur_ptr)->next) { - if (*cur_ptr == ref) + if (*cur_ptr == bp_ref) { found = *cur_ptr; *cur_ptr = (*cur_ptr)->next; @@ -890,7 +1131,7 @@ bool VMBreakInterface::remove(VMBreakPoi assert(found); - VMBreakPoint* brpt = found->brpt; + VMBreakPoint* brpt = found->bp; assert(brpt); if (found->data) @@ -901,22 +1142,23 @@ bool VMBreakInterface::remove(VMBreakPoi if (vm_brpt->find_other_reference(this, brpt)) return true; // There are some other references to the same breakpoint - if (!vm_brpt->remove_breakpoint(brpt)) + if (!breakpoint_remove(brpt)) return false; STD_FREE(brpt); return true; } -VMBreakPointRef* VMBreakInterface::find(jmethodID method, jlocation location) +VMBreakPointRef* +VMBreakInterface::find_reference(jmethodID method, jlocation location) { assert(method); for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { - if (ref->brpt->method && - ref->brpt->method == method && - ref->brpt->location == location) + if (ref->bp->method && + ref->bp->method == method && + ref->bp->location == location) { return ref; } @@ -925,13 +1167,14 @@ VMBreakPointRef* VMBreakInterface::find( return NULL; } -VMBreakPointRef* VMBreakInterface::find(NativeCodePtr addr) +VMBreakPointRef* +VMBreakInterface::find_reference(NativeCodePtr addr) { assert(addr); for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { - if (ref->brpt->addr == addr) + if (ref->bp->addr == addr) { return ref; } @@ -940,13 +1183,14 @@ VMBreakPointRef* VMBreakInterface::find( return NULL; } -VMBreakPointRef* VMBreakInterface::find(VMBreakPoint* brpt) +VMBreakPointRef* +VMBreakInterface::find_reference(VMBreakPoint* brpt) { assert(brpt); for (VMBreakPointRef* ref = m_list; ref; ref = ref->next) { - if (ref->brpt == brpt) + if (ref->bp == brpt) { return ref; } @@ -955,12 +1199,6 @@ VMBreakPointRef* VMBreakInterface::find( return NULL; } -void VMBreakInterface::remove_all() -{ - while (m_list) - remove(m_list); -} - ////////////////////////////////////////////////////////////////////////////// // Helper functions @@ -972,12 +1210,13 @@ get_condition_code(InstructionDisassembl return (ConditionCode)jump_type; } -static bool set_jit_mode_breakpoint(VMBreakPoints* vm_brpt, VMBreakPoint* bp) +static bool set_jit_mode_breakpoint(VMBreakPoint* bp) { assert(bp); // Find native location in the method code Method *m = (Method *)bp->method; + assert(m); assert( m->get_state() == Method::ST_Compiled ); NativeCodePtr np = bp->addr; @@ -1004,6 +1243,7 @@ static bool set_jit_mode_breakpoint(VMBr << method_get_name((Method*)bp->method) << method_get_descriptor((Method*)bp->method) << " :" << bp->location << " :" << bp->addr); + return set_native_breakpoint(bp); } @@ -1013,9 +1253,9 @@ static bool set_native_breakpoint(VMBrea assert(bp->addr); TRACE2("jvmti.break.intf", "Instrumenting native: " - << (bp->method ? class_get_name(method_get_class((Method*)bp->method)) : "" ) + << (bp->method ? class_get_name(method_get_class((Method*)bp->method)) : "(nil)" ) << "." - << (bp->method ? method_get_name((Method*)bp->method) : "" ) + << (bp->method ? method_get_name((Method*)bp->method) : "(nil)" ) << (bp->method ? method_get_descriptor((Method*)bp->method) : "" ) << " :" << bp->location << " :" << bp->addr); @@ -1088,6 +1328,7 @@ #if PLATFORM_POSIX && INSTRUMENTATION_BY #else NativeCodePtr native_location = (NativeCodePtr)regs->get_ip(); #endif + ASSERT_NO_INTERPRETER; TRACE2("jvmti.break", "BREAKPOINT occured: " << native_location); @@ -1095,20 +1336,8 @@ #endif if (!ti->isEnabled() || ti->getPhase() != JVMTI_PHASE_LIVE) return false; - VMBreakPoints* vm_brpt = ti->vm_brpt; - vm_brpt->lock(); - VMBreakPoint* bp = vm_brpt->find_breakpoint(native_location); - if (NULL == bp) - { - vm_brpt->unlock(); - return false; - } - - assert(!interpreter_enabled()); - // Now it is necessary to set up a transition to - // process_native_breakpoint_event from the exception/signal - // handler + // process_native_breakpoint_event from the exception/signal handler VM_thread *vm_thread = p_TLS_vmthread; // Copy original registers to TLS vm_thread->jvmti_saved_exception_registers = *regs; @@ -1117,9 +1346,6 @@ #ifndef _EM64T_ #else regs->rip = (POINTER_SIZE_INT)process_native_breakpoint_event; #endif - - // Breakpoints list lock is not released until it is unlocked - // inside of process_native_breakpoint_event return true; } @@ -1139,7 +1365,7 @@ void jvmti_set_pending_breakpoints(Metho if( !method->get_pending_breakpoints() ) return; - VMBreakPoint* bp = vm_brpt->find_first((jmethodID)method); + VMBreakPoint* bp = vm_brpt->find_method_breakpoint((jmethodID)method); assert(bp); jlocation *locations = (jlocation *)STD_MALLOC(sizeof(jlocation) * @@ -1155,11 +1381,11 @@ void jvmti_set_pending_breakpoints(Metho if (bp->location == locations[iii]) continue; - set_jit_mode_breakpoint(vm_brpt, bp); + set_jit_mode_breakpoint(bp); locations[location_count++] = bp->location; method->remove_pending_breakpoint(); - bp = vm_brpt->find_next(bp, (jmethodID)method); + bp = vm_brpt->find_next_method_breakpoint(bp, (jmethodID)method); } while (NULL != bp); diff --git a/vm/vmcore/src/jvmti/jvmti_method.cpp b/vm/vmcore/src/jvmti/jvmti_method.cpp index 1e3fb4a..f61cf74 100644 --- a/vm/vmcore/src/jvmti/jvmti_method.cpp +++ b/vm/vmcore/src/jvmti/jvmti_method.cpp @@ -534,11 +534,8 @@ jvmtiGetBytecodes(jvmtiEnv* env, LMAutoUnlock lock(vm_brpt->get_lock()); - if (!vm_brpt->has_breakpoint(method)) - return JVMTI_ERROR_NONE; - - for (VMBreakPoint* bpt = vm_brpt->find_first(method); bpt; - bpt = vm_brpt->find_next(bpt, method)) + for (VMBreakPoint* bpt = vm_brpt->find_method_breakpoint(method); bpt; + bpt = vm_brpt->find_next_method_breakpoint(bpt, method)) { (*bytecodes_ptr)[bpt->location] = (unsigned char)bpt->saved_byte; diff --git a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp index dec8359..0dc470a 100644 --- a/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp +++ b/vm/vmcore/src/jvmti/jvmti_pop_frame.cpp @@ -342,7 +342,7 @@ jvmti_relocate_single_step_breakpoints( jit->get_bc_location_for_native(method, ip, &bc); assert(EXE_ERROR_NONE == result); - jvmti_StepLocation locations = {method, bc, ip}; + jvmti_StepLocation locations = {method, ip, bc, false}; jvmti_set_single_step_breakpoints(ti, vm_thread, &locations, 1); } } diff --git a/vm/vmcore/src/jvmti/jvmti_step.cpp b/vm/vmcore/src/jvmti/jvmti_step.cpp index 7019f15..8f1698f 100644 --- a/vm/vmcore/src/jvmti/jvmti_step.cpp +++ b/vm/vmcore/src/jvmti/jvmti_step.cpp @@ -429,8 +429,7 @@ jvmti_SingleStepLocation( VM_thread* thr } // jvmti_SingleStepLocation static void -jvmti_setup_jit_single_step(DebugUtilsTI *ti, VMBreakInterface* intf, - Method* m, jlocation location) +jvmti_setup_jit_single_step(DebugUtilsTI *ti, Method* m, jlocation location) { VM_thread* vm_thread = p_TLS_vmthread; jvmti_StepLocation *locations; @@ -444,18 +443,18 @@ jvmti_setup_jit_single_step(DebugUtilsTI jvmti_set_single_step_breakpoints(ti, vm_thread, locations, locations_count); } -static void jvmti_start_single_step_in_virtual_method(DebugUtilsTI *ti, VMBreakInterface* intf, - VMBreakPointRef* bp_ref) +static void jvmti_start_single_step_in_virtual_method(DebugUtilsTI *ti, VMBreakPoint* bp, + void *data) { VM_thread *vm_thread = p_TLS_vmthread; Registers *regs = &vm_thread->jvmti_saved_exception_registers; // This is a virtual breakpoint set exactly on the call // instruction for the virtual method. In this place it is // possible to determine the target method in runtime - bool *virtual_flag = (bool *)bp_ref->data; + bool* UNREF virtual_flag = (bool *)data; assert(*virtual_flag == true); - InstructionDisassembler *disasm = bp_ref->brpt->disasm; + InstructionDisassembler *disasm = bp->disasm; const InstructionDisassembler::Opnd& op = disasm->get_opnd(0); Method *method; if (op.kind == InstructionDisassembler::Kind_Mem) @@ -504,20 +503,20 @@ #endif } } - TRACE2("jvmti.break.ss", "Removing VIRTUAL single step breakpoint: " << bp_ref->brpt->addr); + TRACE2("jvmti.break.ss", "Removing VIRTUAL single step breakpoint: " << bp->addr); // The determined method is the one which is called by // invokevirtual or invokeinterface bytecodes. It should be // started to be single stepped from the beginning - intf->remove_all(); + jvmti_remove_single_step_breakpoints(ti, vm_thread); jvmti_StepLocation method_start = {(Method *)method, 0}; jvmti_set_single_step_breakpoints(ti, vm_thread, &method_start, 1); } // Callback function for JVMTI single step processing -static bool jvmti_process_jit_single_step_event(VMBreakInterface* intf, VMBreakPointRef* bp_ref) +static bool jvmti_process_jit_single_step_event(TIEnv* UNREF unused_env, + VMBreakPoint* bp, void *data) { - VMBreakPoint* bp = bp_ref->brpt; assert(bp); TRACE2("jvmti.break.ss", "SingleStep occured: " @@ -541,9 +540,9 @@ static bool jvmti_process_jit_single_ste NativeCodePtr addr = bp->addr; assert(addr); - if (NULL != bp_ref->data) + if (NULL != data) { - jvmti_start_single_step_in_virtual_method(ti, intf, bp_ref); + jvmti_start_single_step_in_virtual_method(ti, bp, data); return true; } @@ -574,10 +573,10 @@ static bool jvmti_process_jit_single_ste << method_get_name((Method*)method) << method_get_descriptor((Method*)method) << " :" << location << " :" << addr); + // fire global event - intf->unlock(); func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - intf->lock(); + TRACE2("jvmti.break.ss", "Finished JIT global SingleStep breakpoint callback: " << class_get_name(method_get_class((Method*)method)) << "." @@ -606,10 +605,10 @@ static bool jvmti_process_jit_single_ste << method_get_descriptor((Method*)method) << " :" << location << " :" << addr); found = true; - intf->unlock(); + func((jvmtiEnv*)env, jni_env, (jthread)hThread, method, location); - intf->lock(); + TRACE2("jvmti.break.ss", "Finished JIT local SingleStep breakpoint callback: " << class_get_name(method_get_class((Method*)method)) << "." @@ -625,7 +624,7 @@ static bool jvmti_process_jit_single_ste // Set breakpoints on bytecodes after the current one if (ti->is_single_step_enabled()) - jvmti_setup_jit_single_step(ti, intf, m, location); + jvmti_setup_jit_single_step(ti, m, location); tmn_suspend_disable(); oh_discard_local_handle(hThread); @@ -646,7 +645,7 @@ void jvmti_set_single_step_breakpoints(D // Create SS breakpoints list // Single Step must be processed earlier then Breakpoints ss_state->predicted_breakpoints = - ti->vm_brpt->new_intf(jvmti_process_jit_single_step_event, + ti->vm_brpt->new_intf( NULL, jvmti_process_jit_single_step_event, PRIORITY_SINGLE_STEP_BREAKPOINT, false); assert(ss_state->predicted_breakpoints); } @@ -673,10 +672,11 @@ void jvmti_set_single_step_breakpoints(D } VMBreakPointRef* ref = - ss_state->predicted_breakpoints->add((jmethodID)locations[iii].method, - locations[iii].location, - locations[iii].native_location, - data); + ss_state->predicted_breakpoints->add_reference( + (jmethodID)locations[iii].method, + locations[iii].location, + locations[iii].native_location, + data); assert(ref); } } @@ -689,7 +689,7 @@ void jvmti_remove_single_step_breakpoint TRACE2("jvmti.break.ss", "Remove single step breakpoints"); if (ss_state && ss_state->predicted_breakpoints) - ss_state->predicted_breakpoints->remove_all(); + ss_state->predicted_breakpoints->remove_all_reference(); } jvmtiError jvmti_get_next_bytecodes_from_native(VM_thread *thread,