summaryrefslogtreecommitdiff
path: root/runtime/debugger.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/debugger.h')
-rw-r--r--runtime/debugger.h118
1 files changed, 57 insertions, 61 deletions
diff --git a/runtime/debugger.h b/runtime/debugger.h
index 7c586a4ff9..fd7d46c37e 100644
--- a/runtime/debugger.h
+++ b/runtime/debugger.h
@@ -23,7 +23,6 @@
#include <pthread.h>
-#include <map>
#include <set>
#include <string>
#include <vector>
@@ -32,7 +31,6 @@
#include "jdwp/jdwp.h"
#include "jni.h"
#include "jvalue.h"
-#include "object_callbacks.h"
#include "thread_state.h"
namespace art {
@@ -41,10 +39,10 @@ class Class;
class Object;
class Throwable;
} // namespace mirror
-class AllocRecord;
class ArtField;
class ArtMethod;
class ObjectRegistry;
+class ScopedObjectAccess;
class ScopedObjectAccessUnchecked;
class StackVisitor;
class Thread;
@@ -53,33 +51,32 @@ class Thread;
* Invoke-during-breakpoint support.
*/
struct DebugInvokeReq {
- DebugInvokeReq(mirror::Object* invoke_receiver, mirror::Class* invoke_class,
+ DebugInvokeReq(uint32_t invoke_request_id, JDWP::ObjectId invoke_thread_id,
+ mirror::Object* invoke_receiver, mirror::Class* invoke_class,
ArtMethod* invoke_method, uint32_t invoke_options,
- uint64_t* args, uint32_t args_count)
- : receiver(invoke_receiver), klass(invoke_class), method(invoke_method),
- arg_count(args_count), arg_values(args), options(invoke_options),
- error(JDWP::ERR_NONE), result_tag(JDWP::JT_VOID), result_value(0), exception(0),
- lock("a DebugInvokeReq lock", kBreakpointInvokeLock),
- cond("a DebugInvokeReq condition variable", lock) {
+ uint64_t args[], uint32_t args_count)
+ : request_id(invoke_request_id), thread_id(invoke_thread_id), receiver(invoke_receiver),
+ klass(invoke_class), method(invoke_method), arg_count(args_count), arg_values(args),
+ options(invoke_options), reply(JDWP::expandBufAlloc()) {
}
- /* request */
- GcRoot<mirror::Object> receiver; // not used for ClassType.InvokeMethod
+ ~DebugInvokeReq() {
+ JDWP::expandBufFree(reply);
+ }
+
+ // Request
+ const uint32_t request_id;
+ const JDWP::ObjectId thread_id;
+ GcRoot<mirror::Object> receiver; // not used for ClassType.InvokeMethod.
GcRoot<mirror::Class> klass;
- ArtMethod* method;
+ ArtMethod* const method;
const uint32_t arg_count;
- uint64_t* const arg_values; // will be null if arg_count_ == 0
+ std::unique_ptr<uint64_t[]> arg_values; // will be null if arg_count_ == 0. We take ownership
+ // of this array so we must delete it upon destruction.
const uint32_t options;
- /* result */
- JDWP::JdwpError error;
- JDWP::JdwpTag result_tag;
- uint64_t result_value; // either a primitive value or an ObjectId
- JDWP::ObjectId exception;
-
- /* condition variable to wait on while the method executes */
- Mutex lock DEFAULT_MUTEX_ACQUIRED_AFTER;
- ConditionVariable cond GUARDED_BY(lock);
+ // Reply
+ JDWP::ExpandBuf* const reply;
void VisitRoots(RootVisitor* visitor, const RootInfo& root_info)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -202,19 +199,6 @@ std::ostream& operator<<(std::ostream& os, const DeoptimizationRequest::Kind& rh
class Dbg {
public:
- class TypeCache {
- public:
- // Returns a weak global for the input type. Deduplicates.
- jobject Add(mirror::Class* t) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
- Locks::alloc_tracker_lock_);
- // Clears the type cache and deletes all the weak global refs.
- void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_,
- Locks::alloc_tracker_lock_);
-
- private:
- std::multimap<int32_t, jobject> objects_;
- };
-
static void SetJdwpAllowed(bool allowed);
static void StartJdwp();
@@ -621,19 +605,39 @@ class Dbg {
LOCKS_EXCLUDED(Locks::thread_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Invoke support for commands ClassType.InvokeMethod, ClassType.NewInstance and
- // ObjectReference.InvokeMethod.
- static JDWP::JdwpError InvokeMethod(JDWP::ObjectId thread_id, JDWP::ObjectId object_id,
- JDWP::RefTypeId class_id, JDWP::MethodId method_id,
- uint32_t arg_count, uint64_t* arg_values,
- JDWP::JdwpTag* arg_types, uint32_t options,
- JDWP::JdwpTag* pResultTag, uint64_t* pResultValue,
- JDWP::ObjectId* pExceptObj)
+ /*
+ * Invoke support
+ */
+
+ // Called by the JDWP thread to prepare invocation in the event thread (suspended on an event).
+ // If the information sent by the debugger is incorrect, it will send a reply with the
+ // appropriate error code. Otherwise, it will attach a DebugInvokeReq object to the event thread
+ // and resume it (and possibly other threads depending on the invoke options).
+ // Unlike other commands, the JDWP thread will not send the reply to the debugger (see
+ // JdwpState::ProcessRequest). The reply will be sent by the event thread itself after method
+ // invocation completes (see FinishInvokeMethod). This is required to allow the JDWP thread to
+ // process incoming commands from the debugger while the invocation is still in progress in the
+ // event thread, especially if it gets suspended by a debug event occurring in another thread.
+ static JDWP::JdwpError PrepareInvokeMethod(uint32_t request_id, JDWP::ObjectId thread_id,
+ JDWP::ObjectId object_id, JDWP::RefTypeId class_id,
+ JDWP::MethodId method_id, uint32_t arg_count,
+ uint64_t arg_values[], JDWP::JdwpTag* arg_types,
+ uint32_t options)
LOCKS_EXCLUDED(Locks::thread_list_lock_,
Locks::thread_suspend_count_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Called by the event thread to execute a method prepared by the JDWP thread in the given
+ // DebugInvokeReq object. Once the invocation completes, the event thread attaches a reply
+ // to that DebugInvokeReq object so it can be sent to the debugger only when the event thread
+ // is ready to suspend (see FinishInvokeMethod).
static void ExecuteMethod(DebugInvokeReq* pReq);
+ // Called by the event thread to send the reply of the invoke (created in ExecuteMethod)
+ // before suspending itself. This is to ensure the thread is ready to suspend before the
+ // debugger receives the reply.
+ static void FinishInvokeMethod(DebugInvokeReq* pReq);
+
/*
* DDM support.
*/
@@ -655,19 +659,12 @@ class Dbg {
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
- * Recent allocation tracking support.
+ * Allocation tracking support.
*/
- static void RecordAllocation(Thread* self, mirror::Class* type, size_t byte_count)
- LOCKS_EXCLUDED(Locks::alloc_tracker_lock_)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void SetAllocTrackingEnabled(bool enabled) LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
- static bool IsAllocTrackingEnabled() {
- return recent_allocation_records_ != nullptr;
- }
static jbyteArray GetRecentAllocations()
LOCKS_EXCLUDED(Locks::alloc_tracker_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static size_t HeadIndex() EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
static void DumpRecentAllocations() LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
enum HpifWhen {
@@ -717,6 +714,14 @@ class Dbg {
}
private:
+ static void ExecuteMethodWithoutPendingException(ScopedObjectAccess& soa, DebugInvokeReq* pReq)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static void BuildInvokeReply(JDWP::ExpandBuf* pReply, uint32_t request_id,
+ JDWP::JdwpTag result_tag, uint64_t result_value,
+ JDWP::ObjectId exception)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static JDWP::JdwpError GetLocalValue(const StackVisitor& visitor,
ScopedObjectAccessUnchecked& soa, int slot,
JDWP::JdwpTag tag, uint8_t* buf, size_t width)
@@ -755,11 +760,6 @@ class Dbg {
static bool IsForcedInterpreterNeededForUpcallImpl(Thread* thread, ArtMethod* m)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static AllocRecord* recent_allocation_records_ PT_GUARDED_BY(Locks::alloc_tracker_lock_);
- static size_t alloc_record_max_ GUARDED_BY(Locks::alloc_tracker_lock_);
- static size_t alloc_record_head_ GUARDED_BY(Locks::alloc_tracker_lock_);
- static size_t alloc_record_count_ GUARDED_BY(Locks::alloc_tracker_lock_);
-
// Indicates whether the debugger is making requests.
static bool gDebuggerActive;
@@ -784,9 +784,6 @@ class Dbg {
static size_t* GetReferenceCounterForEvent(uint32_t instrumentation_event);
- // Weak global type cache, TODO improve this.
- static TypeCache type_cache_ GUARDED_BY(Locks::alloc_tracker_lock_);
-
// Instrumentation event reference counters.
// TODO we could use an array instead of having all these dedicated counters. Instrumentation
// events are bits of a mask so we could convert them to array index.
@@ -798,7 +795,6 @@ class Dbg {
static size_t exception_catch_event_ref_count_ GUARDED_BY(Locks::deoptimization_lock_);
static uint32_t instrumentation_events_ GUARDED_BY(Locks::mutator_lock_);
- friend class AllocRecord; // For type_cache_ with proper annotalysis.
DISALLOW_COPY_AND_ASSIGN(Dbg);
};