diff options
Diffstat (limited to 'deps/v8/src/debug.cc')
-rw-r--r-- | deps/v8/src/debug.cc | 603 |
1 files changed, 261 insertions, 342 deletions
diff --git a/deps/v8/src/debug.cc b/deps/v8/src/debug.cc index a7bf765581..2796d2dc1c 100644 --- a/deps/v8/src/debug.cc +++ b/deps/v8/src/debug.cc @@ -20,7 +20,7 @@ #include "src/list.h" #include "src/log.h" #include "src/messages.h" -#include "src/natives.h" +#include "src/snapshot/natives.h" #include "include/v8-debug.h" @@ -60,47 +60,29 @@ static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { } -BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info, - BreakLocatorType type) { - debug_info_ = debug_info; - type_ = type; - reloc_iterator_ = NULL; - reloc_iterator_original_ = NULL; - Reset(); // Initialize the rest of the member variables. -} - - -BreakLocationIterator::~BreakLocationIterator() { - DCHECK(reloc_iterator_ != NULL); - DCHECK(reloc_iterator_original_ != NULL); - delete reloc_iterator_; - delete reloc_iterator_original_; -} - - -// Check whether a code stub with the specified major key is a possible break -// point location when looking for source break locations. -static bool IsSourceBreakStub(Code* code) { - CodeStub::Major major_key = CodeStub::GetMajorKey(code); - return major_key == CodeStub::CallFunction; -} - - -// Check whether a code stub with the specified major key is a possible break -// location. -static bool IsBreakStub(Code* code) { - CodeStub::Major major_key = CodeStub::GetMajorKey(code); - return major_key == CodeStub::CallFunction; +BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info, + BreakLocatorType type) + : debug_info_(debug_info), + type_(type), + reloc_iterator_(debug_info->code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), + reloc_iterator_original_( + debug_info->original_code(), + ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)), + break_index_(-1), + position_(1), + statement_position_(1) { + Next(); } -void BreakLocationIterator::Next() { +void BreakLocation::Iterator::Next() { DisallowHeapAllocation no_gc; DCHECK(!RinfoDone()); // Iterate through reloc info for code and original code stopping at each // breakable code target. - bool first = break_point_ == -1; + bool first = break_index_ == -1; while (!RinfoDone()) { if (!first) RinfoNext(); first = false; @@ -115,8 +97,8 @@ void BreakLocationIterator::Next() { } // Always update the position as we don't want that to be before the // statement position. - position_ = static_cast<int>( - rinfo()->data() - debug_info_->shared()->start_position()); + position_ = static_cast<int>(rinfo()->data() - + debug_info_->shared()->start_position()); DCHECK(position_ >= 0); DCHECK(statement_position_ >= 0); } @@ -131,7 +113,7 @@ void BreakLocationIterator::Next() { position_ = 0; } statement_position_ = position_; - break_point_++; + break_index_++; return; } @@ -143,7 +125,7 @@ void BreakLocationIterator::Next() { Code* code = Code::GetCodeFromTargetAddress(target); if (RelocInfo::IsConstructCall(rmode()) || code->is_call_stub()) { - break_point_++; + break_index_++; return; } @@ -152,144 +134,117 @@ void BreakLocationIterator::Next() { if ((code->is_inline_cache_stub() && !code->is_binary_op_stub() && !code->is_compare_ic_stub() && !code->is_to_boolean_ic_stub())) { - break_point_++; + break_index_++; return; } if (code->kind() == Code::STUB) { - if (IsDebuggerStatement()) { - break_point_++; + if (RelocInfo::IsDebuggerStatement(rmode())) { + break_index_++; + return; + } else if (CodeStub::GetMajorKey(code) == CodeStub::CallFunction) { + break_index_++; return; - } else if (type_ == ALL_BREAK_LOCATIONS) { - if (IsBreakStub(code)) { - break_point_++; - return; - } - } else { - DCHECK(type_ == SOURCE_BREAK_LOCATIONS); - if (IsSourceBreakStub(code)) { - break_point_++; - return; - } } } } - if (IsDebugBreakSlot() && type_ != CALLS_AND_RETURNS) { + if (RelocInfo::IsDebugBreakSlot(rmode()) && type_ != CALLS_AND_RETURNS) { // There is always a possible break point at a debug break slot. - break_point_++; + break_index_++; return; } } } -void BreakLocationIterator::Next(int count) { - while (count > 0) { - Next(); - count--; - } +// Find the break point at the supplied address, or the closest one before +// the address. +BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, + BreakLocatorType type, Address pc) { + Iterator it(debug_info, type); + it.SkipTo(BreakIndexFromAddress(debug_info, type, pc)); + return it.GetBreakLocation(); } // Find the break point at the supplied address, or the closest one before // the address. -void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) { +void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, + BreakLocatorType type, Address pc, + List<BreakLocation>* result_out) { + int break_index = BreakIndexFromAddress(debug_info, type, pc); + Iterator it(debug_info, type); + it.SkipTo(break_index); + int statement_position = it.statement_position(); + while (!it.Done() && it.statement_position() == statement_position) { + result_out->Add(it.GetBreakLocation()); + it.Next(); + } +} + + +int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info, + BreakLocatorType type, Address pc) { // Run through all break points to locate the one closest to the address. - int closest_break_point = 0; + int closest_break = 0; int distance = kMaxInt; - while (!Done()) { + for (Iterator it(debug_info, type); !it.Done(); it.Next()) { // Check if this break point is closer that what was previously found. - if (this->pc() <= pc && pc - this->pc() < distance) { - closest_break_point = break_point(); - distance = static_cast<int>(pc - this->pc()); + if (it.pc() <= pc && pc - it.pc() < distance) { + closest_break = it.break_index(); + distance = static_cast<int>(pc - it.pc()); // Check whether we can't get any closer. if (distance == 0) break; } - Next(); } - - // Move to the break point found. - Reset(); - Next(closest_break_point); + return closest_break; } -// Find the break point closest to the supplied source position. -void BreakLocationIterator::FindBreakLocationFromPosition(int position, - BreakPositionAlignment alignment) { +BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, + BreakLocatorType type, int position, + BreakPositionAlignment alignment) { // Run through all break points to locate the one closest to the source // position. - int closest_break_point = 0; + int closest_break = 0; int distance = kMaxInt; - while (!Done()) { + for (Iterator it(debug_info, type); !it.Done(); it.Next()) { int next_position; - switch (alignment) { - case STATEMENT_ALIGNED: - next_position = this->statement_position(); - break; - case BREAK_POSITION_ALIGNED: - next_position = this->position(); - break; - default: - UNREACHABLE(); - next_position = this->statement_position(); + if (alignment == STATEMENT_ALIGNED) { + next_position = it.statement_position(); + } else { + DCHECK(alignment == BREAK_POSITION_ALIGNED); + next_position = it.position(); } - // Check if this break point is closer that what was previously found. if (position <= next_position && next_position - position < distance) { - closest_break_point = break_point(); + closest_break = it.break_index(); distance = next_position - position; // Check whether we can't get any closer. if (distance == 0) break; } - Next(); } - // Move to the break point found. - Reset(); - Next(closest_break_point); -} - - -void BreakLocationIterator::Reset() { - // Create relocation iterators for the two code objects. - if (reloc_iterator_ != NULL) delete reloc_iterator_; - if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_; - reloc_iterator_ = new RelocIterator( - debug_info_->code(), - ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); - reloc_iterator_original_ = new RelocIterator( - debug_info_->original_code(), - ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE)); - - // Position at the first break point. - break_point_ = -1; - position_ = 1; - statement_position_ = 1; - Next(); -} - - -bool BreakLocationIterator::Done() const { - return RinfoDone(); + Iterator it(debug_info, type); + it.SkipTo(closest_break); + return it.GetBreakLocation(); } -void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { +void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { // If there is not already a real break point here patch code with debug // break. if (!HasBreakPoint()) SetDebugBreak(); DCHECK(IsDebugBreak() || IsDebuggerStatement()); // Set the break point information. - DebugInfo::SetBreakPoint(debug_info_, code_position(), - position(), statement_position(), - break_point_object); + DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, + statement_position_, break_point_object); } -void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { +void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { // Clear the break point information. - DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); + DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object); // If there are no more break points here remove the debug break. if (!HasBreakPoint()) { ClearDebugBreak(); @@ -298,7 +253,7 @@ void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { } -void BreakLocationIterator::SetOneShot() { +void BreakLocation::SetOneShot() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -313,7 +268,7 @@ void BreakLocationIterator::SetOneShot() { } -void BreakLocationIterator::ClearOneShot() { +void BreakLocation::ClearOneShot() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -329,7 +284,7 @@ void BreakLocationIterator::ClearOneShot() { } -void BreakLocationIterator::SetDebugBreak() { +void BreakLocation::SetDebugBreak() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; @@ -339,7 +294,7 @@ void BreakLocationIterator::SetDebugBreak() { // handler as the handler and the function is the same. if (IsDebugBreak()) return; - if (RelocInfo::IsJSReturn(rmode())) { + if (IsExit()) { // Patch the frame exit code with a break point. SetDebugBreakAtReturn(); } else if (IsDebugBreakSlot()) { @@ -353,93 +308,52 @@ void BreakLocationIterator::SetDebugBreak() { } -void BreakLocationIterator::ClearDebugBreak() { +void BreakLocation::ClearDebugBreak() { // Debugger statement always calls debugger. No need to modify it. if (IsDebuggerStatement()) return; - if (RelocInfo::IsJSReturn(rmode())) { - // Restore the frame exit code. - ClearDebugBreakAtReturn(); + if (IsExit()) { + // Restore the frame exit code with a break point. + RestoreFromOriginal(Assembler::kJSReturnSequenceLength); } else if (IsDebugBreakSlot()) { // Restore the code in the break slot. - ClearDebugBreakAtSlot(); + RestoreFromOriginal(Assembler::kDebugBreakSlotLength); } else { - // Patch the IC call. - ClearDebugBreakAtIC(); + // Restore the IC call. + rinfo().set_target_address(original_rinfo().target_address()); + // Some ICs store data in the feedback vector. Clear this to ensure we + // won't miss future stepping requirements. + SharedFunctionInfo* shared = debug_info_->shared(); + shared->feedback_vector()->ClearICSlots(shared); } DCHECK(!IsDebugBreak()); } -bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) { - if (RelocInfo::IsConstructCall(original_rmode())) { - return true; - } else if (RelocInfo::IsCodeTarget(rmode())) { +void BreakLocation::RestoreFromOriginal(int length_in_bytes) { + memcpy(pc(), original_pc(), length_in_bytes); + CpuFeatures::FlushICache(pc(), length_in_bytes); +} + + +bool BreakLocation::IsStepInLocation() const { + if (IsConstructCall()) return true; + if (RelocInfo::IsCodeTarget(rmode())) { HandleScope scope(debug_info_->GetIsolate()); - Address target = original_rinfo()->target_address(); - Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); - if (target_code->kind() == Code::STUB) { - return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction; - } + Handle<Code> target_code = CodeTarget(); return target_code->is_call_stub(); } return false; } -void BreakLocationIterator::PrepareStepIn(Isolate* isolate) { -#ifdef DEBUG - HandleScope scope(isolate); - // Step in can only be prepared if currently positioned on an IC call, - // construct call or CallFunction stub call. - Address target = rinfo()->target_address(); - Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); - // All the following stuff is needed only for assertion checks so the code - // is wrapped in ifdef. - Handle<Code> maybe_call_function_stub = target_code; - if (IsDebugBreak()) { - Address original_target = original_rinfo()->target_address(); - maybe_call_function_stub = - Handle<Code>(Code::GetCodeFromTargetAddress(original_target)); - } - bool is_call_function_stub = - (maybe_call_function_stub->kind() == Code::STUB && - CodeStub::GetMajorKey(*maybe_call_function_stub) == - CodeStub::CallFunction); - - // Step in through construct call requires no changes to the running code. - // Step in through getters/setters should already be prepared as well - // because caller of this function (Debug::PrepareStep) is expected to - // flood the top frame's function with one shot breakpoints. - // Step in through CallFunction stub should also be prepared by caller of - // this function (Debug::PrepareStep) which should flood target function - // with breakpoints. - DCHECK(RelocInfo::IsConstructCall(rmode()) || - target_code->is_inline_cache_stub() || - is_call_function_stub); -#endif -} - - -// Check whether the break point is at a position which will exit the function. -bool BreakLocationIterator::IsExit() const { - return (RelocInfo::IsJSReturn(rmode())); -} - - -bool BreakLocationIterator::HasBreakPoint() { - return debug_info_->HasBreakPoint(code_position()); -} - - -// Check whether there is a debug break at the current position. -bool BreakLocationIterator::IsDebugBreak() { - if (RelocInfo::IsJSReturn(rmode())) { - return IsDebugBreakAtReturn(); +bool BreakLocation::IsDebugBreak() const { + if (IsExit()) { + return rinfo().IsPatchedReturnSequence(); } else if (IsDebugBreakSlot()) { - return IsDebugBreakAtSlot(); + return rinfo().IsPatchedDebugBreakSlotSequence(); } else { - return Debug::IsDebugBreak(rinfo()->target_address()); + return Debug::IsDebugBreak(rinfo().target_address()); } } @@ -491,70 +405,53 @@ static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { } -void BreakLocationIterator::SetDebugBreakAtIC() { +void BreakLocation::SetDebugBreakAtIC() { // Patch the original code with the current address as the current address // might have changed by the inline caching since the code was copied. - original_rinfo()->set_target_address(rinfo()->target_address()); + original_rinfo().set_target_address(rinfo().target_address()); - RelocInfo::Mode mode = rmode(); - if (RelocInfo::IsCodeTarget(mode)) { - Address target = rinfo()->target_address(); - Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); + if (RelocInfo::IsCodeTarget(rmode_)) { + Handle<Code> target_code = CodeTarget(); // Patch the code to invoke the builtin debug break function matching the // calling convention used by the call site. - Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode); - rinfo()->set_target_address(dbgbrk_code->entry()); + Handle<Code> debug_break_code = DebugBreakForIC(target_code, rmode_); + rinfo().set_target_address(debug_break_code->entry()); } } -void BreakLocationIterator::ClearDebugBreakAtIC() { - // Patch the code to the original invoke. - rinfo()->set_target_address(original_rinfo()->target_address()); -} - - -bool BreakLocationIterator::IsDebuggerStatement() { - return RelocInfo::DEBUG_BREAK == rmode(); -} - - -bool BreakLocationIterator::IsDebugBreakSlot() { - return RelocInfo::DEBUG_BREAK_SLOT == rmode(); +Handle<Object> BreakLocation::BreakPointObjects() const { + return debug_info_->GetBreakPointObjects(pc_offset_); } -Object* BreakLocationIterator::BreakPointObjects() { - return debug_info_->GetBreakPointObjects(code_position()); +Handle<Code> BreakLocation::CodeTarget() const { + DCHECK(IsCodeTarget()); + Address target = rinfo().target_address(); + return Handle<Code>(Code::GetCodeFromTargetAddress(target)); } -// Clear out all the debug break code. This is ONLY supposed to be used when -// shutting down the debugger as it will leave the break point information in -// DebugInfo even though the code is patched back to the non break point state. -void BreakLocationIterator::ClearAllDebugBreak() { - while (!Done()) { - ClearDebugBreak(); - Next(); - } +Handle<Code> BreakLocation::OriginalCodeTarget() const { + DCHECK(IsCodeTarget()); + Address target = original_rinfo().target_address(); + return Handle<Code>(Code::GetCodeFromTargetAddress(target)); } -bool BreakLocationIterator::RinfoDone() const { - DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); - return reloc_iterator_->done(); +bool BreakLocation::Iterator::RinfoDone() const { + DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); + return reloc_iterator_.done(); } -void BreakLocationIterator::RinfoNext() { - reloc_iterator_->next(); - reloc_iterator_original_->next(); +void BreakLocation::Iterator::RinfoNext() { + reloc_iterator_.next(); + reloc_iterator_original_.next(); #ifdef DEBUG - DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done()); - if (!reloc_iterator_->done()) { - DCHECK(rmode() == original_rmode()); - } + DCHECK(reloc_iterator_.done() == reloc_iterator_original_.done()); + DCHECK(reloc_iterator_.done() || rmode() == original_rmode()); #endif } @@ -696,9 +593,10 @@ void ScriptCache::HandleWeakScript( void Debug::HandlePhantomDebugInfo( - const v8::PhantomCallbackData<DebugInfoListNode>& data) { - Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug(); + const v8::WeakCallbackInfo<DebugInfoListNode>& data) { DebugInfoListNode* node = data.GetParameter(); + node->ClearInfo(); + Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug(); debug->RemoveDebugInfo(node); #ifdef DEBUG for (DebugInfoListNode* n = debug->debug_info_list_; @@ -713,16 +611,20 @@ void Debug::HandlePhantomDebugInfo( 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<DebugInfo>::cast(global_handles->Create(debug_info)); - typedef PhantomCallbackData<void>::Callback Callback; - GlobalHandles::MakePhantom( - reinterpret_cast<Object**>(debug_info_.location()), this, 0, - reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo)); + debug_info_ = + Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location(); + typedef WeakCallbackInfo<void>::Callback Callback; + GlobalHandles::MakeWeak( + reinterpret_cast<Object**>(debug_info_), this, + reinterpret_cast<Callback>(Debug::HandlePhantomDebugInfo), + v8::WeakCallbackType::kParameter); } -DebugInfoListNode::~DebugInfoListNode() { - GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location())); +void DebugInfoListNode::ClearInfo() { + if (debug_info_ == nullptr) return; + GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_)); + debug_info_ = nullptr; } @@ -744,8 +646,8 @@ bool Debug::CompileDebuggerScript(Isolate* isolate, int index) { // Compile the script. Handle<SharedFunctionInfo> function_info; function_info = Compiler::CompileScript( - source_code, script_name, 0, 0, false, false, context, NULL, NULL, - ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false); + source_code, script_name, 0, 0, false, false, Handle<Object>(), context, + NULL, NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE, false); // Silently ignore stack overflows during compilation. if (function_info.is_null()) { @@ -888,14 +790,14 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { Handle<DebugInfo> debug_info = GetDebugInfo(shared); // Find the break point where execution has stopped. - BreakLocationIterator break_location_iterator(debug_info, - ALL_BREAK_LOCATIONS); - // pc points to the instruction after the current one, possibly a break + // PC points to the instruction after the current one, possibly a break // location as well. So the "- 1" to exclude it from the search. - break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1); + Address call_pc = frame->pc() - 1; + BreakLocation break_location = + BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); // Check whether step next reached a new statement. - if (!StepNextContinue(&break_location_iterator, frame)) { + if (!StepNextContinue(&break_location, frame)) { // Decrease steps left if performing multiple steps. if (thread_local_.step_count_ > 0) { thread_local_.step_count_--; @@ -905,9 +807,8 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { // If there is one or more real break points check whether any of these are // triggered. Handle<Object> break_points_hit(heap->undefined_value(), isolate_); - if (break_location_iterator.HasBreakPoint()) { - Handle<Object> break_point_objects = - Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_); + if (break_location.HasBreakPoint()) { + Handle<Object> break_point_objects = break_location.BreakPointObjects(); break_points_hit = CheckBreakPoints(break_point_objects); } @@ -1092,11 +993,10 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function, DCHECK(*source_position >= 0); // Find the break point and change it. - BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); - it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED); - it.SetBreakPoint(break_point_object); - - *source_position = it.statement_position(); + BreakLocation location = BreakLocation::FromPosition( + debug_info, SOURCE_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED); + *source_position = location.statement_position(); + location.SetBreakPoint(break_point_object); // At least one active break point now. return debug_info->GetBreakPointCount() > 0; @@ -1112,11 +1012,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script, PrepareForBreakPoints(); // Obtain shared function info for the function. - Object* result = FindSharedFunctionInfoInScript(script, *source_position); + Handle<Object> result = + FindSharedFunctionInfoInScript(script, *source_position); if (result->IsUndefined()) return false; // Make sure the function has set up the debug info. - Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result)); + Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { // Return if retrieving debug info failed. return false; @@ -1136,12 +1037,12 @@ bool Debug::SetBreakPointForScript(Handle<Script> script, DCHECK(position >= 0); // Find the break point and change it. - BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); - it.FindBreakLocationFromPosition(position, alignment); - it.SetBreakPoint(break_point_object); + BreakLocation location = BreakLocation::FromPosition( + debug_info, SOURCE_BREAK_LOCATIONS, position, alignment); + location.SetBreakPoint(break_point_object); - position = (alignment == STATEMENT_ALIGNED) ? it.statement_position() - : it.position(); + position = (alignment == STATEMENT_ALIGNED) ? location.statement_position() + : location.position(); *source_position = position + shared->start_position(); @@ -1156,18 +1057,21 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { DebugInfoListNode* node = debug_info_list_; while (node != NULL) { - Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(), - break_point_object); + Handle<Object> result = + DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); if (!result->IsUndefined()) { // Get information in the break point. - BreakPointInfo* break_point_info = BreakPointInfo::cast(result); + Handle<BreakPointInfo> break_point_info = + Handle<BreakPointInfo>::cast(result); Handle<DebugInfo> debug_info = node->debug_info(); // Find the break point and clear it. - BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS); - it.FindBreakLocationFromAddress(debug_info->code()->entry() + - break_point_info->code_position()->value()); - it.ClearBreakPoint(break_point_object); + Address pc = debug_info->code()->entry() + + break_point_info->code_position()->value(); + + BreakLocation location = + BreakLocation::FromAddress(debug_info, SOURCE_BREAK_LOCATIONS, pc); + location.ClearBreakPoint(break_point_object); // If there are no more break points left remove the debug info for this // function. @@ -1182,15 +1086,17 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { } +// Clear out all the debug break code. This is ONLY supposed to be used when +// shutting down the debugger as it will leave the break point information in +// DebugInfo even though the code is patched back to the non break point state. void Debug::ClearAllBreakPoints() { - DebugInfoListNode* node = debug_info_list_; - while (node != NULL) { - // Remove all debug break code. - BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); - it.ClearAllDebugBreak(); - node = node->next(); + for (DebugInfoListNode* node = debug_info_list_; node != NULL; + node = node->next()) { + for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); + !it.Done(); it.Next()) { + it.GetBreakLocation().ClearDebugBreak(); + } } - // Remove all debug info. while (debug_info_list_ != NULL) { RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); @@ -1213,10 +1119,9 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function, } // Flood the function with break points. - BreakLocationIterator it(GetDebugInfo(shared), type); - while (!it.Done()) { - it.SetOneShot(); - it.Next(); + for (BreakLocation::Iterator it(GetDebugInfo(shared), type); !it.Done(); + it.Next()) { + it.GetBreakLocation().SetOneShot(); } } @@ -1284,8 +1189,9 @@ void Debug::FloodHandlerWithOneShot() { } for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) { JavaScriptFrame* frame = it.frame(); - if (frame->HasHandler()) { - // Flood the function with the catch block with break points + int stack_slots = 0; // The computed stack slot count is not used. + if (frame->LookupExceptionHandlerInTable(&stack_slots) > 0) { + // Flood the function with the catch/finally block with break points. FloodWithOneShot(Handle<JSFunction>(frame->function())); return; } @@ -1362,8 +1268,12 @@ void Debug::PrepareStep(StepAction step_action, return; } + List<FrameSummary> frames(FLAG_max_inlining_levels + 1); + frames_it.frame()->Summarize(&frames); + FrameSummary summary = frames.first(); + // Get the debug info (create it if it does not exist). - Handle<JSFunction> function(frame->function()); + Handle<JSFunction> function(summary.function()); Handle<SharedFunctionInfo> shared(function->shared()); if (!EnsureDebugInfo(shared, function)) { // Return if ensuring debug info failed. @@ -1371,47 +1281,38 @@ void Debug::PrepareStep(StepAction step_action, } Handle<DebugInfo> debug_info = GetDebugInfo(shared); - // Find the break location where execution has stopped. - BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS); - // pc points to the instruction after the current one, possibly a break - // location as well. So the "- 1" to exclude it from the search. - it.FindBreakLocationFromAddress(frame->pc() - 1); - // Compute whether or not the target is a call target. bool is_load_or_store = false; bool is_inline_cache_stub = false; bool is_at_restarted_function = false; Handle<Code> call_function_stub; + // 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 = summary.pc() - 1; + BreakLocation location = + BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc); + if (thread_local_.restarter_frame_function_pointer_ == NULL) { - if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) { - bool is_call_target = false; - Address target = it.rinfo()->target_address(); - Code* code = Code::GetCodeFromTargetAddress(target); - if (code->is_call_stub()) { - is_call_target = true; - } - if (code->is_inline_cache_stub()) { - is_inline_cache_stub = true; - is_load_or_store = !is_call_target; - } + if (location.IsCodeTarget()) { + Handle<Code> target_code = location.CodeTarget(); + is_inline_cache_stub = target_code->is_inline_cache_stub(); + is_load_or_store = is_inline_cache_stub && !target_code->is_call_stub(); // Check if target code is CallFunction stub. - Code* maybe_call_function_stub = code; + Handle<Code> maybe_call_function_stub = target_code; // If there is a breakpoint at this line look at the original code to // check if it is a CallFunction stub. - if (it.IsDebugBreak()) { - Address original_target = it.original_rinfo()->target_address(); - maybe_call_function_stub = - Code::GetCodeFromTargetAddress(original_target); + if (location.IsDebugBreak()) { + maybe_call_function_stub = location.OriginalCodeTarget(); } if ((maybe_call_function_stub->kind() == Code::STUB && - CodeStub::GetMajorKey(maybe_call_function_stub) == + CodeStub::GetMajorKey(*maybe_call_function_stub) == CodeStub::CallFunction) || maybe_call_function_stub->is_call_stub()) { // Save reference to the code as we may need it to find out arguments // count for 'step in' later. - call_function_stub = Handle<Code>(maybe_call_function_stub); + call_function_stub = maybe_call_function_stub; } } } else { @@ -1419,14 +1320,14 @@ void Debug::PrepareStep(StepAction step_action, } // If this is the last break code target step out is the only possibility. - if (it.IsExit() || step_action == StepOut) { + if (location.IsExit() || step_action == StepOut) { if (step_action == StepOut) { // Skip step_count frames starting with the current one. while (step_count-- > 0 && !frames_it.done()) { frames_it.Advance(); } } else { - DCHECK(it.IsExit()); + DCHECK(location.IsExit()); frames_it.Advance(); } // Skip builtin functions on the stack. @@ -1443,9 +1344,9 @@ void Debug::PrepareStep(StepAction step_action, // Set target frame pointer. ActivateStepOut(frames_it.frame()); } - } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) || - !call_function_stub.is_null() || is_at_restarted_function) - || step_action == StepNext || step_action == StepMin) { + } else if (!(is_inline_cache_stub || location.IsConstructCall() || + !call_function_stub.is_null() || is_at_restarted_function) || + step_action == StepNext || step_action == StepMin) { // Step next or step min. // Fill the current function with one-shot break points. @@ -1455,7 +1356,7 @@ void Debug::PrepareStep(StepAction step_action, // Remember source position and frame to handle step next. thread_local_.last_statement_position_ = - debug_info->code()->SourceStatementPosition(frame->pc()); + debug_info->code()->SourceStatementPosition(summary.pc()); thread_local_.last_fp_ = frame->UnpaddedFP(); } else { // If there's restarter frame on top of the stack, just get the pointer @@ -1527,12 +1428,20 @@ void Debug::PrepareStep(StepAction step_action, // Object::Get/SetPropertyWithAccessor, otherwise the step action will be // propagated on the next Debug::Break. thread_local_.last_statement_position_ = - debug_info->code()->SourceStatementPosition(frame->pc()); + debug_info->code()->SourceStatementPosition(summary.pc()); thread_local_.last_fp_ = frame->UnpaddedFP(); } // Step in or Step in min - it.PrepareStepIn(isolate_); + // Step in through construct call requires no changes to the running code. + // Step in through getters/setters should already be prepared as well + // because caller of this function (Debug::PrepareStep) is expected to + // flood the top frame's function with one shot breakpoints. + // Step in through CallFunction stub should also be prepared by caller of + // this function (Debug::PrepareStep) which should flood target function + // with breakpoints. + DCHECK(location.IsConstructCall() || is_inline_cache_stub || + !call_function_stub.is_null() || is_at_restarted_function); ActivateStepIn(frame); } } @@ -1544,7 +1453,7 @@ void Debug::PrepareStep(StepAction step_action, // there will be several break points in the same statement when the code is // flooded with one-shot break points. This function helps to perform several // steps before reporting break back to the debugger. -bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, +bool Debug::StepNextContinue(BreakLocation* break_location, JavaScriptFrame* frame) { // StepNext and StepOut shouldn't bring us deeper in code, so last frame // shouldn't be a parent of current frame. @@ -1563,11 +1472,11 @@ bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator, // statement is hit. if (step_action == StepNext || step_action == StepIn) { // Never continue if returning from function. - if (break_location_iterator->IsExit()) return false; + if (break_location->IsExit()) return false; // Continue if we are still on the same frame and in the same statement. int current_statement_position = - break_location_iterator->code()->SourceStatementPosition(frame->pc()); + break_location->code()->SourceStatementPosition(frame->pc()); return thread_local_.last_fp_ == frame->UnpaddedFP() && thread_local_.last_statement_position_ == current_statement_position; } @@ -1585,9 +1494,6 @@ bool Debug::IsDebugBreak(Address addr) { } - - - // Simple function for returning the source positions for active break points. Handle<Object> Debug::GetSourceBreakLocations( Handle<SharedFunctionInfo> shared, @@ -1674,15 +1580,12 @@ void Debug::ClearOneShot() { // The current implementation just runs through all the breakpoints. When the // last break point for a function is removed that function is automatically // removed from the list. - - DebugInfoListNode* node = debug_info_list_; - while (node != NULL) { - BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS); - while (!it.Done()) { - it.ClearOneShot(); - it.Next(); + for (DebugInfoListNode* node = debug_info_list_; node != NULL; + node = node->next()) { + for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS); + !it.Done(); it.Next()) { + it.GetBreakLocation().ClearOneShot(); } - node = node->next(); } } @@ -2098,8 +2001,8 @@ void Debug::PrepareForBreakPoints() { } -Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script, - int position) { +Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, + int position) { // Iterate the heap looking for SharedFunctionInfo generated from the // script. The inner most SharedFunctionInfo containing the source position // for the requested break point is found. @@ -2182,7 +2085,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script, } // End for loop. } // End no-allocation scope. - if (target.is_null()) return heap->undefined_value(); + if (target.is_null()) return isolate_->factory()->undefined_value(); // There will be at least one break point when we are done. has_break_points_ = true; @@ -2198,7 +2101,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script, MaybeHandle<Code> maybe_result = target_function.is_null() ? Compiler::GetUnoptimizedCode(target) : Compiler::GetUnoptimizedCode(target_function); - if (maybe_result.is_null()) return isolate_->heap()->undefined_value(); + if (maybe_result.is_null()) return isolate_->factory()->undefined_value(); } } // End while loop. @@ -2217,7 +2120,7 @@ Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script, } } - return *target; + return target; } @@ -2241,6 +2144,10 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, return false; } + // Make sure IC state is clean. + shared->code()->ClearInlineCaches(); + shared->feedback_vector()->ClearICSlots(*shared); + // Create the debug info object. Handle<DebugInfo> debug_info = isolate->factory()->NewDebugInfo(shared); @@ -2579,7 +2486,7 @@ MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) { } -void Debug::OnThrow(Handle<Object> exception, bool uncaught) { +void Debug::OnThrow(Handle<Object> exception) { if (in_debug_scope() || ignore_events()) return; // Temporarily clear any scheduled_exception to allow evaluating // JavaScript from the debug event handler. @@ -2589,7 +2496,7 @@ void Debug::OnThrow(Handle<Object> exception, bool uncaught) { scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); isolate_->clear_scheduled_exception(); } - OnException(exception, uncaught, isolate_->GetPromiseOnStackOnThrow()); + OnException(exception, isolate_->GetPromiseOnStackOnThrow()); if (!scheduled_exception.is_null()) { isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; } @@ -2602,7 +2509,7 @@ void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) { // Check whether the promise has been marked as having triggered a message. Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); if (JSObject::GetDataProperty(promise, key)->IsUndefined()) { - OnException(value, false, promise); + OnException(value, promise); } } @@ -2617,9 +2524,10 @@ MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler( } -void Debug::OnException(Handle<Object> exception, bool uncaught, - Handle<Object> promise) { - if (!uncaught && promise->IsJSObject()) { +void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { + Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); + bool uncaught = (catch_type == Isolate::NOT_CAUGHT); + if (promise->IsJSObject()) { Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); // Mark the promise as already having triggered a message. Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); @@ -3181,8 +3089,19 @@ void Debug::HandleDebugBreak() { bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && !isolate_->stack_guard()->CheckDebugBreak(); + bool is_debugger_statement = !isolate_->stack_guard()->CheckDebugCommand() && + !isolate_->stack_guard()->CheckDebugBreak(); + isolate_->stack_guard()->ClearDebugBreak(); + if (is_debugger_statement) { + // If we have been called via 'debugger' Javascript statement, + // we might not be prepared for breakpoints. + // TODO(dslomov,yangguo): CheckDebugBreak may race with RequestDebugBreak. + // Revisit this to clean-up. + HandleScope handle_scope(isolate_); + PrepareForBreakPoints(); + } ProcessDebugMessages(debug_command_only); } |