}
void SingleStepControl::VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info) {
- if (method != nullptr) {
- callback(reinterpret_cast<mirror::Object**>(&method), arg, root_info);
+ if (method_ != nullptr) {
+ callback(reinterpret_cast<mirror::Object**>(&method_), arg, root_info);
}
}
-bool SingleStepControl::ContainsDexPc(uint32_t dex_pc) const {
- return dex_pcs.find(dex_pc) == dex_pcs.end();
+void SingleStepControl::AddDexPc(uint32_t dex_pc) {
+ dex_pcs_.insert(dex_pc);
}
-void SingleStepControl::Clear() {
- is_active = false;
- method = nullptr;
- dex_pcs.clear();
+bool SingleStepControl::ContainsDexPc(uint32_t dex_pc) const {
+ return dex_pcs_.find(dex_pc) == dex_pcs_.end();
}
static bool IsBreakpoint(const mirror::ArtMethod* m, uint32_t dex_pc)
// If the debugger is single-stepping one of our threads, check to
// see if we're that thread and we've reached a step point.
const SingleStepControl* single_step_control = thread->GetSingleStepControl();
- DCHECK(single_step_control != nullptr);
- if (single_step_control->is_active) {
+ if (single_step_control != nullptr) {
CHECK(!m->IsNative());
- if (single_step_control->step_depth == JDWP::SD_INTO) {
+ if (single_step_control->GetStepDepth() == JDWP::SD_INTO) {
// Step into method calls. We break when the line number
// or method pointer changes. If we're in SS_MIN mode, we
// always stop.
- if (single_step_control->method != m) {
+ if (single_step_control->GetMethod() != m) {
event_flags |= kSingleStep;
VLOG(jdwp) << "SS new method";
- } else if (single_step_control->step_size == JDWP::SS_MIN) {
+ } else if (single_step_control->GetStepSize() == JDWP::SS_MIN) {
event_flags |= kSingleStep;
VLOG(jdwp) << "SS new instruction";
} else if (single_step_control->ContainsDexPc(dex_pc)) {
event_flags |= kSingleStep;
VLOG(jdwp) << "SS new line";
}
- } else if (single_step_control->step_depth == JDWP::SD_OVER) {
+ } else if (single_step_control->GetStepDepth() == JDWP::SD_OVER) {
// Step over method calls. We break when the line number is
// different and the frame depth is <= the original frame
// depth. (We can't just compare on the method, because we
int stack_depth = GetStackDepth(thread);
- if (stack_depth < single_step_control->stack_depth) {
+ if (stack_depth < single_step_control->GetStackDepth()) {
// Popped up one or more frames, always trigger.
event_flags |= kSingleStep;
VLOG(jdwp) << "SS method pop";
- } else if (stack_depth == single_step_control->stack_depth) {
+ } else if (stack_depth == single_step_control->GetStackDepth()) {
// Same depth, see if we moved.
- if (single_step_control->step_size == JDWP::SS_MIN) {
+ if (single_step_control->GetStepSize() == JDWP::SS_MIN) {
event_flags |= kSingleStep;
VLOG(jdwp) << "SS new instruction";
} else if (single_step_control->ContainsDexPc(dex_pc)) {
}
}
} else {
- CHECK_EQ(single_step_control->step_depth, JDWP::SD_OUT);
+ CHECK_EQ(single_step_control->GetStepDepth(), JDWP::SD_OUT);
// Return from the current method. We break when the frame
// depth pops up.
// function, rather than the end of the returning function.
int stack_depth = GetStackDepth(thread);
- if (stack_depth < single_step_control->stack_depth) {
+ if (stack_depth < single_step_control->GetStackDepth()) {
event_flags |= kSingleStep;
VLOG(jdwp) << "SS method pop";
}
return sts.GetError();
}
- //
- // Work out what Method* we're in, the current line number, and how deep the stack currently
+ // Work out what ArtMethod* we're in, the current line number, and how deep the stack currently
// is for step-out.
- //
-
struct SingleStepStackVisitor : public StackVisitor {
- explicit SingleStepStackVisitor(Thread* thread, SingleStepControl* single_step_control,
- int32_t* line_number)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr), single_step_control_(single_step_control),
- line_number_(line_number) {
- DCHECK_EQ(single_step_control_, thread->GetSingleStepControl());
- single_step_control_->method = nullptr;
- single_step_control_->stack_depth = 0;
+ explicit SingleStepStackVisitor(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ : StackVisitor(thread, nullptr), stack_depth(0), method(nullptr), line_number(-1) {
}
// TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
bool VisitFrame() NO_THREAD_SAFETY_ANALYSIS {
mirror::ArtMethod* m = GetMethod();
if (!m->IsRuntimeMethod()) {
- ++single_step_control_->stack_depth;
- if (single_step_control_->method == nullptr) {
+ ++stack_depth;
+ if (method == nullptr) {
mirror::DexCache* dex_cache = m->GetDeclaringClass()->GetDexCache();
- single_step_control_->method = m;
- *line_number_ = -1;
+ method = m;
if (dex_cache != nullptr) {
const DexFile& dex_file = *dex_cache->GetDexFile();
- *line_number_ = dex_file.GetLineNumFromPC(m, GetDexPc());
+ line_number = dex_file.GetLineNumFromPC(m, GetDexPc());
}
}
}
return true;
}
- SingleStepControl* const single_step_control_;
- int32_t* const line_number_;
+ int stack_depth;
+ mirror::ArtMethod* method;
+ int32_t line_number;
};
Thread* const thread = sts.GetThread();
- SingleStepControl* const single_step_control = thread->GetSingleStepControl();
- DCHECK(single_step_control != nullptr);
- int32_t line_number = -1;
- SingleStepStackVisitor visitor(thread, single_step_control, &line_number);
+ SingleStepStackVisitor visitor(thread);
visitor.WalkStack();
- //
// Find the dex_pc values that correspond to the current line, for line-based single-stepping.
- //
-
struct DebugCallbackContext {
- explicit DebugCallbackContext(SingleStepControl* single_step_control_cb, int32_t line_number_cb,
- const DexFile::CodeItem* code_item)
+ explicit DebugCallbackContext(SingleStepControl* single_step_control_cb,
+ int32_t line_number_cb, const DexFile::CodeItem* code_item)
: single_step_control_(single_step_control_cb), line_number_(line_number_cb),
code_item_(code_item), last_pc_valid(false), last_pc(0) {
}
} else if (context->last_pc_valid) { // and the line number is new
// Add everything from the last entry up until here to the set
for (uint32_t dex_pc = context->last_pc; dex_pc < address; ++dex_pc) {
- context->single_step_control_->dex_pcs.insert(dex_pc);
+ context->single_step_control_->AddDexPc(dex_pc);
}
context->last_pc_valid = false;
}
if (last_pc_valid) {
size_t end = code_item_->insns_size_in_code_units_;
for (uint32_t dex_pc = last_pc; dex_pc < end; ++dex_pc) {
- single_step_control_->dex_pcs.insert(dex_pc);
+ single_step_control_->AddDexPc(dex_pc);
}
}
}
bool last_pc_valid;
uint32_t last_pc;
};
- single_step_control->dex_pcs.clear();
- mirror::ArtMethod* m = single_step_control->method;
+
+ // Allocate single step.
+ SingleStepControl* single_step_control = new SingleStepControl(step_size, step_depth,
+ visitor.stack_depth,
+ visitor.method);
+ CHECK(single_step_control != nullptr) << "Failed to allocate SingleStepControl";
+ mirror::ArtMethod* m = single_step_control->GetMethod();
+ const int32_t line_number = visitor.line_number;
if (!m->IsNative()) {
const DexFile::CodeItem* const code_item = m->GetCodeItem();
DebugCallbackContext context(single_step_control, line_number, code_item);
DebugCallbackContext::Callback, nullptr, &context);
}
- //
- // Everything else...
- //
-
- single_step_control->step_size = step_size;
- single_step_control->step_depth = step_depth;
- single_step_control->is_active = true;
+ // Activate single-step in the thread.
+ thread->ActivateSingleStepControl(single_step_control);
if (VLOG_IS_ON(jdwp)) {
VLOG(jdwp) << "Single-step thread: " << *thread;
- VLOG(jdwp) << "Single-step step size: " << single_step_control->step_size;
- VLOG(jdwp) << "Single-step step depth: " << single_step_control->step_depth;
- VLOG(jdwp) << "Single-step current method: " << PrettyMethod(single_step_control->method);
+ VLOG(jdwp) << "Single-step step size: " << single_step_control->GetStepSize();
+ VLOG(jdwp) << "Single-step step depth: " << single_step_control->GetStepDepth();
+ VLOG(jdwp) << "Single-step current method: " << PrettyMethod(single_step_control->GetMethod());
VLOG(jdwp) << "Single-step current line: " << line_number;
- VLOG(jdwp) << "Single-step current stack depth: " << single_step_control->stack_depth;
+ VLOG(jdwp) << "Single-step current stack depth: " << single_step_control->GetStackDepth();
VLOG(jdwp) << "Single-step dex_pc values:";
- for (uint32_t dex_pc : single_step_control->dex_pcs) {
+ for (uint32_t dex_pc : single_step_control->GetDexPcs()) {
VLOG(jdwp) << StringPrintf(" %#x", dex_pc);
}
}
JDWP::JdwpError error;
Thread* thread = DecodeThread(soa, thread_id, &error);
if (error == JDWP::ERR_NONE) {
- SingleStepControl* single_step_control = thread->GetSingleStepControl();
- DCHECK(single_step_control != nullptr);
- single_step_control->Clear();
+ thread->DeactivateSingleStepControl();
}
}
};
// Thread local data-structure that holds fields for controlling single-stepping.
-struct SingleStepControl {
- SingleStepControl()
- : is_active(false), step_size(JDWP::SS_MIN), step_depth(JDWP::SD_INTO),
- method(nullptr), stack_depth(0) {
+class SingleStepControl {
+ public:
+ SingleStepControl(JDWP::JdwpStepSize step_size, JDWP::JdwpStepDepth step_depth,
+ int stack_depth, mirror::ArtMethod* method)
+ : step_size_(step_size), step_depth_(step_depth),
+ stack_depth_(stack_depth), method_(method) {
}
- // Are we single-stepping right now?
- bool is_active;
+ JDWP::JdwpStepSize GetStepSize() const {
+ return step_size_;
+ }
- // See JdwpStepSize and JdwpStepDepth for details.
- JDWP::JdwpStepSize step_size;
- JDWP::JdwpStepDepth step_depth;
+ JDWP::JdwpStepDepth GetStepDepth() const {
+ return step_depth_;
+ }
- // The location this single-step was initiated from.
- // A single-step is initiated in a suspended thread. We save here the current method and the
- // set of DEX pcs associated to the source line number where the suspension occurred.
- // This is used to support SD_INTO and SD_OVER single-step depths so we detect when a single-step
- // causes the execution of an instruction in a different method or at a different line number.
- mirror::ArtMethod* method;
- std::set<uint32_t> dex_pcs;
+ int GetStackDepth() const {
+ return stack_depth_;
+ }
- // The stack depth when this single-step was initiated. This is used to support SD_OVER and SD_OUT
- // single-step depth.
- int stack_depth;
+ mirror::ArtMethod* GetMethod() const {
+ return method_;
+ }
+
+ const std::set<uint32_t>& GetDexPcs() const {
+ return dex_pcs_;
+ }
void VisitRoots(RootCallback* callback, void* arg, const RootInfo& root_info)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool ContainsDexPc(uint32_t dex_pc) const;
+ void AddDexPc(uint32_t dex_pc);
- void Clear();
+ bool ContainsDexPc(uint32_t dex_pc) const;
private:
+ // See JdwpStepSize and JdwpStepDepth for details.
+ const JDWP::JdwpStepSize step_size_;
+ const JDWP::JdwpStepDepth step_depth_;
+
+ // The stack depth when this single-step was initiated. This is used to support SD_OVER and SD_OUT
+ // single-step depth.
+ const int stack_depth_;
+
+ // The location this single-step was initiated from.
+ // A single-step is initiated in a suspended thread. We save here the current method and the
+ // set of DEX pcs associated to the source line number where the suspension occurred.
+ // This is used to support SD_INTO and SD_OVER single-step depths so we detect when a single-step
+ // causes the execution of an instruction in a different method or at a different line number.
+ mirror::ArtMethod* method_;
+ std::set<uint32_t> dex_pcs_;
+
DISALLOW_COPY_AND_ASSIGN(SingleStepControl);
};