target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN ? builtins->Return_DebugBreak() : builtins->Slot_DebugBreak(); DebugCodegen::PatchDebugBreakSlot(isolate(), rinfo()->pc(), target); } void CodeBreakIterator::ClearDebugBreak() { DebugBreakType debug_break_type = GetDebugBreakType(); if (debug_break_type == DEBUGGER_STATEMENT) return; DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); DebugCodegen::ClearDebugBreakSlot(isolate(), rinfo()->pc()); } bool CodeBreakIterator::IsDebugBreak() { DebugBreakType debug_break_type = GetDebugBreakType(); if (debug_break_type == DEBUGGER_STATEMENT) return false; DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc()); } BreakLocation CodeBreakIterator::GetBreakLocation() { Handle code(AbstractCode::cast(debug_info_->DebugCode())); return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); } BytecodeArrayBreakIterator::BytecodeArrayBreakIterator( Handle debug_info, BreakLocatorType type) : BreakIterator(debug_info, type), source_position_iterator_( debug_info->DebugBytecodeArray()->source_position_table()) { // There is at least one break location. DCHECK(!Done()); Next(); } void BytecodeArrayBreakIterator::Next() { DisallowHeapAllocation no_gc; DCHECK(!Done()); bool first = break_index_ == -1; while (!Done()) { if (!first) source_position_iterator_.Advance(); first = false; if (Done()) return; position_ = source_position_iterator_.source_position().ScriptOffset(); if (source_position_iterator_.is_statement()) { statement_position_ = position_; } DCHECK(position_ >= 0); DCHECK(statement_position_ >= 0); DebugBreakType type = GetDebugBreakType(); if (type == NOT_DEBUG_BREAK) continue; if (break_locator_type_ == ALL_BREAK_LOCATIONS) break; DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_); if (type == DEBUG_BREAK_SLOT_AT_CALL) break; if (type == DEBUG_BREAK_SLOT_AT_RETURN) break; } break_index_++; } DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() { BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); if (bytecode == interpreter::Bytecode::kDebugger) { return DEBUGGER_STATEMENT; } else if (bytecode == interpreter::Bytecode::kReturn) { return DEBUG_BREAK_SLOT_AT_RETURN; } else if (bytecode == interpreter::Bytecode::kTailCall) { return isolate()->is_tail_call_elimination_enabled() ? DEBUG_BREAK_SLOT_AT_TAIL_CALL : DEBUG_BREAK_SLOT_AT_CALL; } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { return DEBUG_BREAK_SLOT_AT_CALL; } else if (source_position_iterator_.is_statement()) { return DEBUG_BREAK_SLOT; } else { return NOT_DEBUG_BREAK; } } void BytecodeArrayBreakIterator::SkipToPosition( int position, BreakPositionAlignment alignment) { BytecodeArrayBreakIterator it(debug_info_, break_locator_type_); SkipTo(it.BreakIndexFromPosition(position, alignment)); } void BytecodeArrayBreakIterator::SetDebugBreak() { DebugBreakType debug_break_type = GetDebugBreakType(); if (debug_break_type == DEBUGGER_STATEMENT) return; DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return; interpreter::Bytecode debugbreak = interpreter::Bytecodes::GetDebugBreak(bytecode); bytecode_array->set(code_offset(), interpreter::Bytecodes::ToByte(debugbreak)); } void BytecodeArrayBreakIterator::ClearDebugBreak() { DebugBreakType debug_break_type = GetDebugBreakType(); if (debug_break_type == DEBUGGER_STATEMENT) return; DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); BytecodeArray* original = debug_info_->OriginalBytecodeArray(); bytecode_array->set(code_offset(), original->get(code_offset())); } bool BytecodeArrayBreakIterator::IsDebugBreak() { DebugBreakType debug_break_type = GetDebugBreakType(); if (debug_break_type == DEBUGGER_STATEMENT) return false; DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); return interpreter::Bytecodes::IsDebugBreak(bytecode); } BreakLocation BytecodeArrayBreakIterator::GetBreakLocation() { Handle code( AbstractCode::cast(debug_info_->DebugBytecodeArray())); return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); } 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_ = kNoSourcePosition; thread_local_.last_fp_ = 0; thread_local_.target_fp_ = 0; thread_local_.return_value_ = Handle(); clear_suspended_generator(); // TODO(isolates): frames_are_dropped_? base::NoBarrier_Store(&thread_local_.current_debug_scope_, static_cast(0)); } char* Debug::ArchiveDebug(char* storage) { // Simply reset state. Don't archive anything. ThreadInit(); return storage + ArchiveSpacePerThread(); } char* Debug::RestoreDebug(char* storage) { // Simply reset state. Don't restore anything. ThreadInit(); return storage + ArchiveSpacePerThread(); } int Debug::ArchiveSpacePerThread() { return 0; } void Debug::Iterate(ObjectVisitor* v) { v->VisitPointer(&thread_local_.suspended_generator_); } 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; // TODO(yangguo): we rely on the fact that first context snapshot is usable // as debug context. This dependency is gone once we remove // debug context completely. static const int kFirstContextSnapshotIndex = 0; Handle context = isolate_->bootstrapper()->CreateEnvironment( MaybeHandle(), v8::Local(), &no_extensions, kFirstContextSnapshotIndex, 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(JavaScriptFrame* frame) { HandleScope scope(isolate_); // 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(), isolate_); // Find the break location where execution has stopped. BreakLocation location = BreakLocation::FromFrame(debug_info, frame); // Find actual break points, if any, and trigger debug break event. Handle break_points_hit = CheckBreakPoints(debug_info, &location); if (!break_points_hit->IsUndefined(isolate_)) { // 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 = false; switch (step_action) { case StepNone: return; case StepOut: // Step out has not reached the target frame yet. if (current_fp < target_fp) return; step_break = true; break; case StepNext: // Step next should not break in a deeper frame. if (current_fp < target_fp) return; // For step-next, a tail call is like a return and should break. step_break = location.IsTailCall(); // Fall through. case StepIn: { FrameSummary summary = FrameSummary::GetFirst(frame); int offset = summary.code_offset(); step_break = step_break || location.IsReturn() || (current_fp != last_fp) || (thread_local_.last_statement_position_ != summary.abstract_code()->SourceStatementPosition(offset)); 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); } } // Find break point objects for this location, if any, and evaluate them. // Return an array of break point objects that evaluated true. Handle Debug::CheckBreakPoints(Handle debug_info, BreakLocation* location, bool* has_break_points) { Factory* factory = isolate_->factory(); bool has_break_points_to_check = break_points_active_ && location->HasBreakPoint(debug_info); if (has_break_points) *has_break_points = has_break_points_to_check; if (!has_break_points_to_check) return factory->undefined_value(); Handle break_point_objects = debug_info->GetBreakPointObjects(location->position()); // 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(isolate_)); 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 break_point_object(array->get(i), isolate_); if (CheckBreakPoint(break_point_object)) { break_points_hit->set(break_points_hit_count++, *break_point_object); } } } else { break_points_hit = factory->NewFixedArray(1); if (CheckBreakPoint(break_point_objects)) { break_points_hit->set(break_points_hit_count++, *break_point_objects); } } if (break_points_hit_count == 0) return factory->undefined_value(); Handle result = factory->NewJSArrayWithElements(break_points_hit); result->set_length(Smi::FromInt(break_points_hit_count)); return result; } bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { // A break location is considered muted if break locations on the current // statement have at least one break point, and all of these break points // evaluate to false. Aside from not triggering a debug break event at the // break location, we also do not trigger one for debugger statements, nor // an exception event on exception at this location. Object* fun = frame->function(); if (!fun->IsJSFunction()) return false; JSFunction* function = JSFunction::cast(fun); if (!function->shared()->HasDebugInfo()) return false; HandleScope scope(isolate_); Handle debug_info(function->shared()->GetDebugInfo()); // Enter the debugger. DebugScope debug_scope(this); if (debug_scope.failed()) return false; List break_locations; BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); bool has_break_points_at_all = false; for (int i = 0; i < break_locations.length(); i++) { bool has_break_points; Handle check_result = CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); has_break_points_at_all |= has_break_points; if (has_break_points && !check_result->IsUndefined(isolate_)) return false; } return has_break_points_at_all; } MaybeHandle Debug::CallFunction(const char* name, int argc, Handle args[]) { PostponeInterruptsScope no_interrupts(isolate_); AssertDebugContext(); Handle holder = Handle::cast(isolate_->natives_utils_object()); Handle fun = Handle::cast( JSReceiver::GetProperty(isolate_, holder, name).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(isolate_); } 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. *source_position = FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); // At least one active break point now. DCHECK(debug_info->GetBreakPointCount() > 0); ClearBreakPoints(debug_info); ApplyBreakPoints(debug_info); feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); return true; } bool Debug::SetBreakPointForScript(Handle 登录后可以享受更多权益 您还没有登录,登录后您可以: 收藏Android系统代码 收藏喜欢的文章 多个平台共享账号 去登录 首次使用?从这里 注册
您还没有登录,登录后您可以:
首次使用?从这里 注册