target = IsReturn() ? builtins->Return_DebugBreak() : builtins->Slot_DebugBreak(); DebugCodegen::PatchDebugBreakSlot(isolate, pc(), target); DCHECK(IsDebugBreak()); } void BreakLocation::ClearDebugBreak() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; DCHECK(IsDebugBreakSlot()); DebugCodegen::ClearDebugBreakSlot(debug_info_->GetIsolate(), pc()); DCHECK(!IsDebugBreak()); } bool BreakLocation::IsDebugBreak() const { if (IsDebuggerStatement()) return false; DCHECK(IsDebugBreakSlot()); return rinfo().IsPatchedDebugBreakSlotSequence(); } Handle BreakLocation::BreakPointObjects() const { return debug_info_->GetBreakPointObjects(pc_offset_); } void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { uint32_t mask = 1 << feature; // Only count one sample per feature and isolate. if (bitfield_ & mask) return; isolate_->counters()->debug_feature_usage()->AddSample(feature); bitfield_ |= mask; } // Threading support. void Debug::ThreadInit() { thread_local_.break_count_ = 0; thread_local_.break_id_ = 0; thread_local_.break_frame_id_ = StackFrame::NO_ID; thread_local_.last_step_action_ = StepNone; thread_local_.last_statement_position_ = RelocInfo::kNoPosition; thread_local_.last_fp_ = 0; thread_local_.target_fp_ = 0; thread_local_.step_in_enabled_ = false; // TODO(isolates): frames_are_dropped_? base::NoBarrier_Store(&thread_local_.current_debug_scope_, static_cast(0)); } char* Debug::ArchiveDebug(char* storage) { char* to = storage; MemCopy(to, reinterpret_cast(&thread_local_), sizeof(ThreadLocal)); ThreadInit(); return storage + ArchiveSpacePerThread(); } char* Debug::RestoreDebug(char* storage) { char* from = storage; MemCopy(reinterpret_cast(&thread_local_), from, sizeof(ThreadLocal)); return storage + ArchiveSpacePerThread(); } int Debug::ArchiveSpacePerThread() { return sizeof(ThreadLocal); } DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { // Globalize the request debug info object and make it weak. GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles(); debug_info_ = Handle::cast(global_handles->Create(debug_info)).location(); } DebugInfoListNode::~DebugInfoListNode() { if (debug_info_ == nullptr) return; GlobalHandles::Destroy(reinterpret_cast(debug_info_)); debug_info_ = nullptr; } bool Debug::Load() { // Return if debugger is already loaded. if (is_loaded()) return true; // Bail out if we're already in the process of compiling the native // JavaScript source code for the debugger. if (is_suppressed_) return false; SuppressDebug while_loading(this); // Disable breakpoints and interrupts while compiling and running the // debugger scripts including the context creation code. DisableBreak disable(this, true); PostponeInterruptsScope postpone(isolate_); // Create the debugger context. HandleScope scope(isolate_); ExtensionConfiguration no_extensions; Handle context = isolate_->bootstrapper()->CreateEnvironment( MaybeHandle(), v8::Local(), &no_extensions, DEBUG_CONTEXT); // Fail if no context could be created. if (context.is_null()) return false; debug_context_ = Handle::cast( isolate_->global_handles()->Create(*context)); feature_tracker()->Track(DebugFeatureTracker::kActive); return true; } void Debug::Unload() { ClearAllBreakPoints(); ClearStepping(); // Return debugger is not loaded. if (!is_loaded()) return; // Clear debugger context global handle. GlobalHandles::Destroy(Handle::cast(debug_context_).location()); debug_context_ = Handle(); } void Debug::Break(Arguments args, JavaScriptFrame* frame) { HandleScope scope(isolate_); DCHECK(args.length() == 0); // Initialize LiveEdit. LiveEdit::InitializeThreadLocal(this); // Just continue if breaks are disabled or debugger cannot be loaded. if (break_disabled()) return; // Enter the debugger. DebugScope debug_scope(this); if (debug_scope.failed()) return; // Postpone interrupt during breakpoint processing. PostponeInterruptsScope postpone(isolate_); // Get the debug info (create it if it does not exist). Handle function(frame->function()); Handle shared(function->shared()); if (!EnsureDebugInfo(shared, function)) { // Return if we failed to retrieve the debug info. return; } Handle debug_info(shared->GetDebugInfo()); // Find the break location where execution has stopped. // PC points to the instruction after the current one, possibly a break // location as well. So the "- 1" to exclude it from the search. Address call_pc = frame->pc() - 1; BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); // Find actual break points, if any, and trigger debug break event. if (break_points_active_ && location.HasBreakPoint()) { Handle break_point_objects = location.BreakPointObjects(); Handle break_points_hit = CheckBreakPoints(break_point_objects); if (!break_points_hit->IsUndefined()) { // Clear all current stepping setup. ClearStepping(); // Notify the debug event listeners. OnDebugBreak(break_points_hit, false); return; } } // No break point. Check for stepping. StepAction step_action = last_step_action(); Address current_fp = frame->UnpaddedFP(); Address target_fp = thread_local_.target_fp_; Address last_fp = thread_local_.last_fp_; bool step_break = true; switch (step_action) { case StepNone: return; case StepOut: // Step out has not reached the target frame yet. if (current_fp < target_fp) return; break; case StepNext: // Step next should not break in a deeper frame. if (current_fp < target_fp) return; // Fall through. case StepIn: step_break = location.IsReturn() || (current_fp != last_fp) || (thread_local_.last_statement_position_ != location.code()->SourceStatementPosition(frame->pc())); break; case StepFrame: step_break = current_fp != last_fp; break; } // Clear all current stepping setup. ClearStepping(); if (step_break) { // Notify the debug event listeners. OnDebugBreak(isolate_->factory()->undefined_value(), false); } else { // Re-prepare to continue. PrepareStep(step_action); } } // Check the break point objects for whether one or more are actually // triggered. This function returns a JSArray with the break point objects // which is triggered. Handle Debug::CheckBreakPoints(Handle break_point_objects) { Factory* factory = isolate_->factory(); // Count the number of break points hit. If there are multiple break points // they are in a FixedArray. Handle break_points_hit; int break_points_hit_count = 0; DCHECK(!break_point_objects->IsUndefined()); if (break_point_objects->IsFixedArray()) { Handle array(FixedArray::cast(*break_point_objects)); break_points_hit = factory->NewFixedArray(array->length()); for (int i = 0; i < array->length(); i++) { Handle o(array->get(i), isolate_); if (CheckBreakPoint(o)) { break_points_hit->set(break_points_hit_count++, *o); } } } else { break_points_hit = factory->NewFixedArray(1); if (CheckBreakPoint(break_point_objects)) { break_points_hit->set(break_points_hit_count++, *break_point_objects); } } // Return undefined if no break points were triggered. if (break_points_hit_count == 0) { return factory->undefined_value(); } // Return break points hit as a JSArray. Handle result = factory->NewJSArrayWithElements(break_points_hit); result->set_length(Smi::FromInt(break_points_hit_count)); return result; } MaybeHandle Debug::CallFunction(const char* name, int argc, Handle args[]) { PostponeInterruptsScope no_interrupts(isolate_); AssertDebugContext(); Handle holder = isolate_->natives_utils_object(); Handle fun = Handle::cast( Object::GetProperty(isolate_, holder, name, STRICT).ToHandleChecked()); Handle undefined = isolate_->factory()->undefined_value(); return Execution::TryCall(isolate_, fun, undefined, argc, args); } // Check whether a single break point object is triggered. bool Debug::CheckBreakPoint(Handle break_point_object) { Factory* factory = isolate_->factory(); HandleScope scope(isolate_); // Ignore check if break point object is not a JSObject. if (!break_point_object->IsJSObject()) return true; // Get the break id as an object. Handle break_id = factory->NewNumberFromInt(Debug::break_id()); // Call IsBreakPointTriggered. Handle argv[] = { break_id, break_point_object }; Handle result; if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv) .ToHandle(&result)) { return false; } // Return whether the break point is triggered. return result->IsTrue(); } bool Debug::SetBreakPoint(Handle function, Handle break_point_object, int* source_position) { HandleScope scope(isolate_); // Make sure the function is compiled and has set up the debug info. Handle shared(function->shared()); if (!EnsureDebugInfo(shared, function)) { // Return if retrieving debug info failed. return true; } Handle debug_info(shared->GetDebugInfo()); // Source positions starts with zero. DCHECK(*source_position >= 0); // Find the break point and change it. BreakLocation location = BreakLocation::FromPosition( debug_info, *source_position, STATEMENT_ALIGNED); *source_position = location.statement_position(); location.SetBreakPoint(break_point_object); feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); // At least one active break point now. return debug_info->GetBreakPointCount() > 0; } bool Debug::SetBreakPointForScript(Handle 登录后可以享受更多权益 您还没有登录,登录后您可以: 收藏Android系统代码 收藏喜欢的文章 多个平台共享账号 去登录 首次使用?从这里 注册
您还没有登录,登录后您可以:
首次使用?从这里 注册