diff options
Diffstat (limited to 'deps/v8/src/debug')
-rw-r--r-- | deps/v8/src/debug/arm/debug-arm.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/arm64/debug-arm64.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-evaluate.cc | 7 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-frames.cc | 51 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-frames.h | 9 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-scopes.cc | 26 | ||||
-rw-r--r-- | deps/v8/src/debug/debug-scopes.h | 5 | ||||
-rw-r--r-- | deps/v8/src/debug/debug.cc | 519 | ||||
-rw-r--r-- | deps/v8/src/debug/debug.h | 147 | ||||
-rw-r--r-- | deps/v8/src/debug/debug.js | 81 | ||||
-rw-r--r-- | deps/v8/src/debug/ia32/debug-ia32.cc | 3 | ||||
-rw-r--r-- | deps/v8/src/debug/liveedit.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/mips/debug-mips.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/mips64/debug-mips64.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/mirrors.js | 2 | ||||
-rw-r--r-- | deps/v8/src/debug/ppc/debug-ppc.cc | 4 | ||||
-rw-r--r-- | deps/v8/src/debug/x64/debug-x64.cc | 3 | ||||
-rw-r--r-- | deps/v8/src/debug/x87/debug-x87.cc | 3 |
18 files changed, 546 insertions, 334 deletions
diff --git a/deps/v8/src/debug/arm/debug-arm.cc b/deps/v8/src/debug/arm/debug-arm.cc index 2d4cbf13d7..5fdda4fedc 100644 --- a/deps/v8/src/debug/arm/debug-arm.cc +++ b/deps/v8/src/debug/arm/debug-arm.cc @@ -62,6 +62,10 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, patcher.masm()->blx(ip); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + Instr current_instr = Assembler::instr_at(pc); + return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/arm64/debug-arm64.cc b/deps/v8/src/debug/arm64/debug-arm64.cc index c2b60a9326..3e4b67c938 100644 --- a/deps/v8/src/debug/arm64/debug-arm64.cc +++ b/deps/v8/src/debug/arm64/debug-arm64.cc @@ -74,6 +74,10 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, patcher.blr(ip0); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + Instruction* current_instr = reinterpret_cast<Instruction*>(pc); + return !current_instr->IsNop(Assembler::DEBUG_BREAK_NOP); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/debug-evaluate.cc b/deps/v8/src/debug/debug-evaluate.cc index e19b93eebe..1134c9dd68 100644 --- a/deps/v8/src/debug/debug-evaluate.cc +++ b/deps/v8/src/debug/debug-evaluate.cc @@ -111,7 +111,7 @@ MaybeHandle<Object> DebugEvaluate::Evaluate( // Skip the global proxy as it has no properties and always delegates to the // real global object. if (result->IsJSGlobalProxy()) { - PrototypeIterator iter(isolate, result); + PrototypeIterator iter(isolate, Handle<JSGlobalProxy>::cast(result)); // TODO(verwaest): This will crash when the global proxy is detached. result = PrototypeIterator::GetCurrent<JSObject>(iter); } @@ -128,7 +128,7 @@ DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate, inlined_jsframe_index_(inlined_jsframe_index) { FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); Handle<JSFunction> local_function = - handle(JSFunction::cast(frame_inspector.GetFunction())); + Handle<JSFunction>::cast(frame_inspector.GetFunction()); Handle<Context> outer_context(local_function->context()); native_context_ = Handle<Context>(outer_context->native_context()); Handle<JSFunction> global_function(native_context_->closure()); @@ -302,8 +302,7 @@ void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject( if (maybe.FromJust()) return; // FunctionGetArguments can't throw an exception. - Handle<JSObject> arguments = - Handle<JSObject>::cast(Accessors::FunctionGetArguments(function)); + Handle<JSObject> arguments = Accessors::FunctionGetArguments(function); Handle<String> arguments_str = isolate_->factory()->arguments_string(); JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments, NONE) diff --git a/deps/v8/src/debug/debug-frames.cc b/deps/v8/src/debug/debug-frames.cc index 012d291622..25634be8d2 100644 --- a/deps/v8/src/debug/debug-frames.cc +++ b/deps/v8/src/debug/debug-frames.cc @@ -15,6 +15,7 @@ FrameInspector::FrameInspector(JavaScriptFrame* frame, has_adapted_arguments_ = frame_->has_adapted_arguments(); is_bottommost_ = inlined_jsframe_index == 0; is_optimized_ = frame_->is_optimized(); + is_interpreted_ = frame_->is_interpreted(); // Calculate the deoptimized frame. if (frame->is_optimized()) { // TODO(turbofan): Revisit once we support deoptimization. @@ -44,33 +45,41 @@ int FrameInspector::GetParametersCount() { : frame_->ComputeParametersCount(); } - -Object* FrameInspector::GetFunction() { - return is_optimized_ ? deoptimized_frame_->GetFunction() : frame_->function(); +Handle<Object> FrameInspector::GetFunction() { + return is_optimized_ ? deoptimized_frame_->GetFunction() + : handle(frame_->function(), isolate_); } - -Object* FrameInspector::GetParameter(int index) { +Handle<Object> FrameInspector::GetParameter(int index) { return is_optimized_ ? deoptimized_frame_->GetParameter(index) - : frame_->GetParameter(index); + : handle(frame_->GetParameter(index), isolate_); } - -Object* FrameInspector::GetExpression(int index) { +Handle<Object> FrameInspector::GetExpression(int index) { // TODO(turbofan): Revisit once we support deoptimization. if (frame_->LookupCode()->is_turbofanned() && frame_->function()->shared()->asm_function() && !FLAG_turbo_asm_deoptimization) { - return isolate_->heap()->undefined_value(); + return isolate_->factory()->undefined_value(); } return is_optimized_ ? deoptimized_frame_->GetExpression(index) - : frame_->GetExpression(index); + : handle(frame_->GetExpression(index), isolate_); } int FrameInspector::GetSourcePosition() { - return is_optimized_ ? deoptimized_frame_->GetSourcePosition() - : frame_->LookupCode()->SourcePosition(frame_->pc()); + if (is_optimized_) { + return deoptimized_frame_->GetSourcePosition(); + } else if (is_interpreted_) { + InterpretedFrame* frame = reinterpret_cast<InterpretedFrame*>(frame_); + BytecodeArray* bytecode_array = + frame->function()->shared()->bytecode_array(); + return bytecode_array->SourcePosition(frame->GetBytecodeOffset()); + } else { + Code* code = frame_->LookupCode(); + int offset = static_cast<int>(frame_->pc() - code->instruction_start()); + return code->SourcePosition(offset); + } } @@ -80,9 +89,9 @@ bool FrameInspector::IsConstructor() { : frame_->IsConstructor(); } - -Object* FrameInspector::GetContext() { - return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context(); +Handle<Object> FrameInspector::GetContext() { + return is_optimized_ ? deoptimized_frame_->GetContext() + : handle(frame_->context(), isolate_); } @@ -92,6 +101,7 @@ void FrameInspector::SetArgumentsFrame(JavaScriptFrame* frame) { DCHECK(has_adapted_arguments_); frame_ = frame; is_optimized_ = frame_->is_optimized(); + is_interpreted_ = frame_->is_interpreted(); DCHECK(!is_optimized_); } @@ -109,10 +119,10 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target, Handle<String> name(scope_info->ParameterName(i)); if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; - Handle<Object> value(i < GetParametersCount() - ? GetParameter(i) - : isolate_->heap()->undefined_value(), - isolate_); + Handle<Object> value = + i < GetParametersCount() + ? GetParameter(i) + : Handle<Object>::cast(isolate_->factory()->undefined_value()); DCHECK(!value->IsTheHole()); JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); @@ -122,8 +132,7 @@ void FrameInspector::MaterializeStackLocals(Handle<JSObject> target, for (int i = 0; i < scope_info->StackLocalCount(); ++i) { if (scope_info->LocalIsSynthetic(i)) continue; Handle<String> name(scope_info->StackLocalName(i)); - Handle<Object> value(GetExpression(scope_info->StackLocalIndex(i)), - isolate_); + Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i)); if (value->IsTheHole()) value = isolate_->factory()->undefined_value(); JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check(); diff --git a/deps/v8/src/debug/debug-frames.h b/deps/v8/src/debug/debug-frames.h index c0d20bbd1d..c04fd2b6bf 100644 --- a/deps/v8/src/debug/debug-frames.h +++ b/deps/v8/src/debug/debug-frames.h @@ -21,12 +21,12 @@ class FrameInspector { ~FrameInspector(); int GetParametersCount(); - Object* GetFunction(); - Object* GetParameter(int index); - Object* GetExpression(int index); + Handle<Object> GetFunction(); + Handle<Object> GetParameter(int index); + Handle<Object> GetExpression(int index); int GetSourcePosition(); bool IsConstructor(); - Object* GetContext(); + Handle<Object> GetContext(); JavaScriptFrame* GetArgumentsFrame() { return frame_; } void SetArgumentsFrame(JavaScriptFrame* frame); @@ -48,6 +48,7 @@ class FrameInspector { DeoptimizedFrameInfo* deoptimized_frame_; Isolate* isolate_; bool is_optimized_; + bool is_interpreted_; bool is_bottommost_; bool has_adapted_arguments_; diff --git a/deps/v8/src/debug/debug-scopes.cc b/deps/v8/src/debug/debug-scopes.cc index 15a0594009..e785384a42 100644 --- a/deps/v8/src/debug/debug-scopes.cc +++ b/deps/v8/src/debug/debug-scopes.cc @@ -28,7 +28,7 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, return; } - context_ = Handle<Context>(Context::cast(frame_inspector->GetContext())); + context_ = Handle<Context>::cast(frame_inspector->GetContext()); // Catch the case when the debugger stops in an internal function. Handle<JSFunction> function = GetFunction(); @@ -58,12 +58,8 @@ ScopeIterator::ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector, // return, which requires a debug info to be available. Handle<DebugInfo> debug_info(shared_info->GetDebugInfo()); - // 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 = GetFrame()->pc() - 1; - // Find the break point where execution has stopped. - BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); + BreakLocation location = BreakLocation::FromFrame(debug_info, GetFrame()); ignore_nested_scopes = location.IsReturn(); } @@ -462,7 +458,8 @@ MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() { isolate_->factory()->NewJSObject(isolate_->object_function()); frame_inspector_->MaterializeStackLocals(local_scope, function); - Handle<Context> frame_context(Context::cast(frame_inspector_->GetContext())); + Handle<Context> frame_context = + Handle<Context>::cast(frame_inspector_->GetContext()); HandleScope scope(isolate_); Handle<SharedFunctionInfo> shared(function->shared()); @@ -471,7 +468,7 @@ MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() { if (!scope_info->HasContext()) return local_scope; // Third fill all context locals. - Handle<Context> function_context(frame_context->declaration_context()); + Handle<Context> function_context(frame_context->closure_context()); CopyContextLocalsToScopeObject(scope_info, function_context, local_scope); // Finally copy any properties from the function context extension. @@ -480,8 +477,8 @@ MaybeHandle<JSObject> ScopeIterator::MaterializeLocalScope() { function_context->has_extension() && !function_context->IsNativeContext()) { bool success = CopyContextExtensionToScopeObject( - handle(function_context->extension_object(), isolate_), - local_scope, JSReceiver::INCLUDE_PROTOS); + handle(function_context->extension_object(), isolate_), local_scope, + INCLUDE_PROTOS); if (!success) return MaybeHandle<JSObject>(); } @@ -510,8 +507,7 @@ Handle<JSObject> ScopeIterator::MaterializeClosure() { // be variables introduced by eval. if (context->has_extension()) { bool success = CopyContextExtensionToScopeObject( - handle(context->extension_object(), isolate_), closure_scope, - JSReceiver::OWN_ONLY); + handle(context->extension_object(), isolate_), closure_scope, OWN_ONLY); DCHECK(success); USE(success); } @@ -559,8 +555,7 @@ Handle<JSObject> ScopeIterator::MaterializeBlockScope() { // Fill all extension variables. if (context->extension_object() != nullptr) { bool success = CopyContextExtensionToScopeObject( - handle(context->extension_object()), block_scope, - JSReceiver::OWN_ONLY); + handle(context->extension_object()), block_scope, OWN_ONLY); DCHECK(success); USE(success); } @@ -798,10 +793,9 @@ void ScopeIterator::CopyContextLocalsToScopeObject( } } - bool ScopeIterator::CopyContextExtensionToScopeObject( Handle<JSObject> extension, Handle<JSObject> scope_object, - JSReceiver::KeyCollectionType type) { + KeyCollectionType type) { Handle<FixedArray> keys; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate_, keys, JSReceiver::GetKeys(extension, type, ENUMERABLE_STRINGS), diff --git a/deps/v8/src/debug/debug-scopes.h b/deps/v8/src/debug/debug-scopes.h index d4e335a2a5..fbdf632687 100644 --- a/deps/v8/src/debug/debug-scopes.h +++ b/deps/v8/src/debug/debug-scopes.h @@ -96,8 +96,7 @@ class ScopeIterator { } inline Handle<JSFunction> GetFunction() { - return Handle<JSFunction>( - JSFunction::cast(frame_inspector_->GetFunction())); + return Handle<JSFunction>::cast(frame_inspector_->GetFunction()); } static bool InternalizedStringMatch(void* key1, void* key2) { @@ -139,7 +138,7 @@ class ScopeIterator { Handle<JSObject> scope_object); bool CopyContextExtensionToScopeObject(Handle<JSObject> extension, Handle<JSObject> scope_object, - JSReceiver::KeyCollectionType type); + KeyCollectionType type); DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator); }; diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc index bd45b71551..93c914c3f8 100644 --- a/deps/v8/src/debug/debug.cc +++ b/deps/v8/src/debug/debug.cc @@ -16,6 +16,8 @@ #include "src/frames-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/global-handles.h" +#include "src/interpreter/bytecodes.h" +#include "src/interpreter/interpreter.h" #include "src/isolate-inl.h" #include "src/list.h" #include "src/log.h" @@ -58,29 +60,39 @@ static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) { return v8::Utils::ToLocal(native_context); } - -BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo, - int position, int statement_position) +BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, DebugBreakType type, + int code_offset, int position, + int statement_position) : debug_info_(debug_info), - pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())), - rmode_(rinfo->rmode()), - data_(rinfo->data()), + code_offset_(code_offset), + type_(type), position_(position), statement_position_(statement_position) {} +BreakLocation::Iterator* BreakLocation::GetIterator( + Handle<DebugInfo> debug_info, BreakLocatorType type) { + if (debug_info->abstract_code()->IsBytecodeArray()) { + return new BytecodeArrayIterator(debug_info, type); + } else { + return new CodeIterator(debug_info, type); + } +} -BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info, - BreakLocatorType type) +BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info) : debug_info_(debug_info), - reloc_iterator_(debug_info->code(), GetModeMask(type)), break_index_(-1), position_(1), - statement_position_(1) { + statement_position_(1) {} + +BreakLocation::CodeIterator::CodeIterator(Handle<DebugInfo> debug_info, + BreakLocatorType type) + : Iterator(debug_info), + reloc_iterator_(debug_info->abstract_code()->GetCode(), + GetModeMask(type)) { if (!Done()) Next(); } - -int BreakLocation::Iterator::GetModeMask(BreakLocatorType type) { +int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) { int mask = 0; mask |= RelocInfo::ModeMask(RelocInfo::POSITION); mask |= RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION); @@ -93,13 +105,11 @@ int BreakLocation::Iterator::GetModeMask(BreakLocatorType type) { return mask; } - -void BreakLocation::Iterator::Next() { +void BreakLocation::CodeIterator::Next() { DisallowHeapAllocation no_gc; DCHECK(!Done()); - // Iterate through reloc info for code and original code stopping at each - // breakable code target. + // Iterate through reloc info stopping at each breakable code target. bool first = break_index_ == -1; while (!Done()) { if (!first) reloc_iterator_.next(); @@ -141,43 +151,154 @@ void BreakLocation::Iterator::Next() { break_index_++; } +BreakLocation BreakLocation::CodeIterator::GetBreakLocation() { + DebugBreakType type; + if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) { + type = DEBUG_BREAK_SLOT_AT_RETURN; + } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) { + type = DEBUG_BREAK_SLOT_AT_CALL; + } else if (RelocInfo::IsDebuggerStatement(rmode())) { + type = DEBUGGER_STATEMENT; + } else if (RelocInfo::IsDebugBreakSlot(rmode())) { + type = DEBUG_BREAK_SLOT; + } else { + type = NOT_DEBUG_BREAK; + } + return BreakLocation(debug_info_, type, code_offset(), position(), + statement_position()); +} + +BreakLocation::BytecodeArrayIterator::BytecodeArrayIterator( + Handle<DebugInfo> debug_info, BreakLocatorType type) + : Iterator(debug_info), + source_position_iterator_( + debug_info->abstract_code()->GetBytecodeArray()), + break_locator_type_(type), + start_position_(debug_info->shared()->start_position()) { + if (!Done()) Next(); +} + +void BreakLocation::BytecodeArrayIterator::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() - start_position_; + if (source_position_iterator_.is_statement()) { + statement_position_ = position_; + } + DCHECK(position_ >= 0); + DCHECK(statement_position_ >= 0); + break_index_++; + + enum 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 || + type == DEBUG_BREAK_SLOT_AT_RETURN) { + break; + } + } +} + +BreakLocation::DebugBreakType +BreakLocation::BytecodeArrayIterator::GetDebugBreakType() { + BytecodeArray* bytecode_array = debug_info_->original_bytecode_array(); + 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 (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; + } +} + +BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() { + return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(), + position(), statement_position()); +} // Find the break point at the supplied address, or the closest one before // the address. -BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info, - Address pc) { - Iterator it(debug_info, ALL_BREAK_LOCATIONS); - it.SkipTo(BreakIndexFromAddress(debug_info, pc)); - return it.GetBreakLocation(); +BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info, + int offset) { + base::SmartPointer<Iterator> it(GetIterator(debug_info)); + it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset)); + return it->GetBreakLocation(); } +FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { + List<FrameSummary> frames(FLAG_max_inlining_levels + 1); + frame->Summarize(&frames); + return frames.first(); +} + +int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) { + // Code offset points to the instruction after the call. Subtract 1 to + // exclude that instruction from the search. For bytecode, the code offset + // still points to the call. + return is_interpreted ? code_offset : code_offset - 1; +} + +BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, + JavaScriptFrame* frame) { + FrameSummary summary = GetFirstFrameSummary(frame); + int call_offset = + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted()); + return FromCodeOffset(debug_info, call_offset); +} // Find the break point at the supplied address, or the closest one before // the address. -void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info, - Address pc, - List<BreakLocation>* result_out) { - int break_index = BreakIndexFromAddress(debug_info, pc); - Iterator it(debug_info, ALL_BREAK_LOCATIONS); - 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(); +void BreakLocation::FromCodeOffsetSameStatement( + Handle<DebugInfo> debug_info, int offset, List<BreakLocation>* result_out) { + int break_index = BreakIndexFromCodeOffset(debug_info, offset); + base::SmartPointer<Iterator> it(GetIterator(debug_info)); + 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(); + } +} + + +void BreakLocation::AllForStatementPosition(Handle<DebugInfo> debug_info, + int statement_position, + List<BreakLocation>* result_out) { + for (base::SmartPointer<Iterator> it(GetIterator(debug_info)); !it->Done(); + it->Next()) { + if (it->statement_position() == statement_position) { + result_out->Add(it->GetBreakLocation()); + } } } - -int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info, - Address pc) { +int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, + int offset) { // Run through all break points to locate the one closest to the address. int closest_break = 0; int distance = kMaxInt; - for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) { + DCHECK(0 <= offset && offset < debug_info->abstract_code()->Size()); + for (base::SmartPointer<Iterator> it(GetIterator(debug_info)); !it->Done(); + it->Next()) { // Check if this break point is closer that what was previously found. - if (it.pc() <= pc && pc - it.pc() < distance) { - closest_break = it.break_index(); - distance = static_cast<int>(pc - it.pc()); + if (it->code_offset() <= offset && offset - it->code_offset() < distance) { + closest_break = it->break_index(); + distance = offset - it->code_offset(); // Check whether we can't get any closer. if (distance == 0) break; } @@ -191,28 +312,26 @@ BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info, BreakPositionAlignment alignment) { // Run through all break points to locate the one closest to the source // position. - int closest_break = 0; int distance = kMaxInt; - - for (Iterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); it.Next()) { + base::SmartPointer<Iterator> it(GetIterator(debug_info)); + BreakLocation closest_break = it->GetBreakLocation(); + while (!it->Done()) { int next_position; if (alignment == STATEMENT_ALIGNED) { - next_position = it.statement_position(); + next_position = it->statement_position(); } else { DCHECK(alignment == BREAK_POSITION_ALIGNED); - next_position = it.position(); + next_position = it->position(); } if (position <= next_position && next_position - position < distance) { - closest_break = it.break_index(); + closest_break = it->GetBreakLocation(); distance = next_position - position; // Check whether we can't get any closer. if (distance == 0) break; } + it->Next(); } - - Iterator it(debug_info, ALL_BREAK_LOCATIONS); - it.SkipTo(closest_break); - return it.GetBreakLocation(); + return closest_break; } @@ -222,14 +341,14 @@ void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) { if (!HasBreakPoint()) SetDebugBreak(); DCHECK(IsDebugBreak() || IsDebuggerStatement()); // Set the break point information. - DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_, + DebugInfo::SetBreakPoint(debug_info_, code_offset_, position_, statement_position_, break_point_object); } void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) { // Clear the break point information. - DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object); + DebugInfo::ClearBreakPoint(debug_info_, code_offset_, break_point_object); // If there are no more break points here remove the debug break. if (!HasBreakPoint()) { ClearDebugBreak(); @@ -280,11 +399,23 @@ void BreakLocation::SetDebugBreak() { if (IsDebugBreak()) return; DCHECK(IsDebugBreakSlot()); - Isolate* isolate = debug_info_->GetIsolate(); - Builtins* builtins = isolate->builtins(); - Handle<Code> target = - IsReturn() ? builtins->Return_DebugBreak() : builtins->Slot_DebugBreak(); - DebugCodegen::PatchDebugBreakSlot(isolate, pc(), target); + if (abstract_code()->IsCode()) { + Code* code = abstract_code()->GetCode(); + DCHECK(code->kind() == Code::FUNCTION); + Builtins* builtins = isolate()->builtins(); + Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak() + : builtins->Slot_DebugBreak(); + Address pc = code->instruction_start() + code_offset(); + DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target); + } else { + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); + interpreter::Bytecode bytecode = + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); + interpreter::Bytecode debugbreak = + interpreter::Bytecodes::GetDebugBreak(bytecode); + bytecode_array->set(code_offset(), + interpreter::Bytecodes::ToByte(debugbreak)); + } DCHECK(IsDebugBreak()); } @@ -294,7 +425,16 @@ void BreakLocation::ClearDebugBreak() { if (IsDebuggerStatement()) return; DCHECK(IsDebugBreakSlot()); - DebugCodegen::ClearDebugBreakSlot(debug_info_->GetIsolate(), pc()); + if (abstract_code()->IsCode()) { + Code* code = abstract_code()->GetCode(); + DCHECK(code->kind() == Code::FUNCTION); + Address pc = code->instruction_start() + code_offset(); + DebugCodegen::ClearDebugBreakSlot(isolate(), pc); + } else { + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); + BytecodeArray* original = debug_info_->original_bytecode_array(); + bytecode_array->set(code_offset(), original->get(code_offset())); + } DCHECK(!IsDebugBreak()); } @@ -302,15 +442,24 @@ void BreakLocation::ClearDebugBreak() { bool BreakLocation::IsDebugBreak() const { if (IsDebuggerStatement()) return false; DCHECK(IsDebugBreakSlot()); - return rinfo().IsPatchedDebugBreakSlotSequence(); + if (abstract_code()->IsCode()) { + Code* code = abstract_code()->GetCode(); + DCHECK(code->kind() == Code::FUNCTION); + Address pc = code->instruction_start() + code_offset(); + return DebugCodegen::DebugBreakSlotIsPatched(pc); + } else { + BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); + interpreter::Bytecode bytecode = + interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); + return interpreter::Bytecodes::IsDebugBreak(bytecode); + } } Handle<Object> BreakLocation::BreakPointObjects() const { - return debug_info_->GetBreakPointObjects(pc_offset_); + return debug_info_->GetBreakPointObjects(code_offset_); } - void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { uint32_t mask = 1 << feature; // Only count one sample per feature and isolate. @@ -444,22 +593,16 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { Handle<DebugInfo> 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); + BreakLocation location = BreakLocation::FromFrame(debug_info, frame); // Find actual break points, if any, and trigger debug break event. - if (break_points_active_ && location.HasBreakPoint()) { - Handle<Object> break_point_objects = location.BreakPointObjects(); - Handle<Object> 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; - } + Handle<Object> break_points_hit = CheckBreakPoints(&location); + 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. @@ -480,11 +623,14 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { // Step next should not break in a deeper frame. if (current_fp < target_fp) return; // Fall through. - case StepIn: + case StepIn: { + FrameSummary summary = GetFirstFrameSummary(frame); + int offset = summary.code_offset(); step_break = location.IsReturn() || (current_fp != last_fp) || (thread_local_.last_statement_position_ != - location.code()->SourceStatementPosition(frame->pc())); + location.abstract_code()->SourceStatementPosition(offset)); break; + } case StepFrame: step_break = current_fp != last_fp; break; @@ -503,12 +649,17 @@ void Debug::Break(Arguments args, JavaScriptFrame* frame) { } -// 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<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { +// Find break point objects for this location, if any, and evaluate them. +// Return an array of break point objects that evaluated true. +Handle<Object> Debug::CheckBreakPoints(BreakLocation* location, + bool* has_break_points) { Factory* factory = isolate_->factory(); + bool has_break_points_to_check = + break_points_active_ && location->HasBreakPoint(); + if (has_break_points) *has_break_points = has_break_points_to_check; + if (!has_break_points_to_check) return factory->undefined_value(); + Handle<Object> break_point_objects = location->BreakPointObjects(); // Count the number of break points hit. If there are multiple break points // they are in a FixedArray. Handle<FixedArray> break_points_hit; @@ -518,9 +669,9 @@ Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); break_points_hit = factory->NewFixedArray(array->length()); for (int i = 0; i < array->length(); i++) { - Handle<Object> o(array->get(i), isolate_); - if (CheckBreakPoint(o)) { - break_points_hit->set(break_points_hit_count++, *o); + Handle<Object> break_point_object(array->get(i), isolate_); + if (CheckBreakPoint(break_point_object)) { + break_points_hit->set(break_points_hit_count++, *break_point_object); } } } else { @@ -529,25 +680,51 @@ Handle<Object> Debug::CheckBreakPoints(Handle<Object> 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. + if (break_points_hit_count == 0) return factory->undefined_value(); Handle<JSArray> 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<DebugInfo> debug_info(function->shared()->GetDebugInfo()); + // Enter the debugger. + DebugScope debug_scope(this); + if (debug_scope.failed()) return false; + BreakLocation current_position = BreakLocation::FromFrame(debug_info, frame); + List<BreakLocation> break_locations; + BreakLocation::AllForStatementPosition( + debug_info, current_position.statement_position(), &break_locations); + bool has_break_points_at_all = false; + for (int i = 0; i < break_locations.length(); i++) { + bool has_break_points; + Handle<Object> check_result = + CheckBreakPoints(&break_locations[i], &has_break_points); + has_break_points_at_all |= has_break_points; + if (has_break_points && !check_result->IsUndefined()) return false; + } + return has_break_points_at_all; +} + + MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, Handle<Object> args[]) { PostponeInterruptsScope no_interrupts(isolate_); AssertDebugContext(); Handle<Object> holder = isolate_->natives_utils_object(); Handle<JSFunction> fun = Handle<JSFunction>::cast( - Object::GetProperty(isolate_, holder, name, STRICT).ToHandleChecked()); + Object::GetProperty(isolate_, holder, name).ToHandleChecked()); Handle<Object> undefined = isolate_->factory()->undefined_value(); return Execution::TryCall(isolate_, fun, undefined, argc, args); } @@ -668,11 +845,8 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { Handle<BreakPointInfo>::cast(result); Handle<DebugInfo> debug_info = node->debug_info(); - // Find the break point and clear it. - Address pc = - debug_info->code()->entry() + break_point_info->code_position(); - - BreakLocation location = BreakLocation::FromAddress(debug_info, pc); + BreakLocation location = BreakLocation::FromCodeOffset( + debug_info, break_point_info->code_offset()); location.ClearBreakPoint(break_point_object); // If there are no more break points left remove the debug info for this @@ -694,9 +868,10 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { void Debug::ClearAllBreakPoints() { 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(); + for (base::SmartPointer<BreakLocation::Iterator> it( + BreakLocation::GetIterator(node->debug_info())); + !it->Done(); it->Next()) { + it->GetBreakLocation().ClearDebugBreak(); } } // Remove all debug info. @@ -727,8 +902,10 @@ void Debug::FloodWithOneShot(Handle<JSFunction> function, // Flood the function with break points. Handle<DebugInfo> debug_info(shared->GetDebugInfo()); - for (BreakLocation::Iterator it(debug_info, type); !it.Done(); it.Next()) { - it.GetBreakLocation().SetOneShot(); + for (base::SmartPointer<BreakLocation::Iterator> it( + BreakLocation::GetIterator(debug_info, type)); + !it->Done(); it->Next()) { + it->GetBreakLocation().SetOneShot(); } } @@ -751,13 +928,6 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) { } -FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { - List<FrameSummary> frames(FLAG_max_inlining_levels + 1); - frame->Summarize(&frames); - return frames.first(); -} - - void Debug::PrepareStepIn(Handle<JSFunction> function) { if (!is_active()) return; if (last_step_action() < StepIn) return; @@ -779,8 +949,7 @@ void Debug::PrepareStepOnThrow() { JavaScriptFrameIterator it(isolate_); while (!it.done()) { JavaScriptFrame* frame = it.frame(); - int stack_slots = 0; // The computed stack slot count is not used. - if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) break; + if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; it.Advance(); } @@ -843,18 +1012,21 @@ void Debug::PrepareStep(StepAction step_action) { Handle<DebugInfo> debug_info(shared->GetDebugInfo()); // Refresh frame summary if the code has been recompiled for debugging. - if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); + if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { + summary = GetFirstFrameSummary(frame); + } - // 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, call_pc); + int call_offset = + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted()); + BreakLocation location = + BreakLocation::FromCodeOffset(debug_info, call_offset); // At a return statement we will step out either way. if (location.IsReturn()) step_action = StepOut; thread_local_.last_statement_position_ = - debug_info->code()->SourceStatementPosition(summary.pc()); + debug_info->abstract_code()->SourceStatementPosition( + summary.code_offset()); thread_local_.last_fp_ = frame->UnpaddedFP(); switch (step_action) { @@ -961,9 +1133,10 @@ void Debug::ClearOneShot() { // removed from the list. 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(); + for (base::SmartPointer<BreakLocation::Iterator> it( + BreakLocation::GetIterator(node->debug_info())); + !it->Done(); it->Next()) { + it->GetBreakLocation().ClearOneShot(); } } } @@ -1070,6 +1243,15 @@ class RedirectActiveFunctions : public ThreadVisitor { if (frame->is_optimized()) continue; if (!function->Inlines(shared_)) continue; + if (frame->is_interpreted()) { + InterpretedFrame* interpreted_frame = + reinterpret_cast<InterpretedFrame*>(frame); + BytecodeArray* debug_copy = + shared_->GetDebugInfo()->abstract_code()->GetBytecodeArray(); + interpreted_frame->PatchBytecodeArray(debug_copy); + continue; + } + Code* frame_code = frame->LookupCode(); DCHECK(frame_code->kind() == Code::FUNCTION); if (frame_code->has_debug_break_slots()) continue; @@ -1127,11 +1309,15 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { // Make sure we abort incremental marking. isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, "prepare for break points"); + bool is_interpreted = shared->HasBytecodeArray(); { + // TODO(yangguo): with bytecode, we still walk the heap to find all + // optimized code for the function to deoptimize. We can probably be + // smarter here and avoid the heap walk. HeapIterator iterator(isolate_->heap()); HeapObject* obj; - bool include_generators = shared->is_generator(); + bool include_generators = !is_interpreted && shared->is_generator(); while ((obj = iterator.next())) { if (obj->IsJSFunction()) { @@ -1140,6 +1326,7 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { Deoptimizer::DeoptimizeFunction(function); } + if (is_interpreted) continue; if (function->shared() == *shared) functions.Add(handle(function)); } else if (include_generators && obj->IsJSGeneratorObject()) { JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj); @@ -1155,7 +1342,12 @@ bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { } } - if (!shared->HasDebugCode()) { + // We do not need to replace code to debug bytecode. + DCHECK(!is_interpreted || functions.length() == 0); + DCHECK(!is_interpreted || suspended_generators.length() == 0); + + // We do not need to recompile to debug bytecode. + if (!is_interpreted && !shared->HasDebugCode()) { DCHECK(functions.length() > 0); if (!Compiler::CompileDebugCode(functions.first())) return false; } @@ -1326,10 +1518,16 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, return false; } - if (!PrepareFunctionForBreakPoints(shared)) return false; - - CreateDebugInfo(shared); - + if (shared->HasBytecodeArray()) { + // To prepare bytecode for debugging, we already need to have the debug + // info (containing the debug copy) upfront, but since we do not recompile, + // preparing for break points cannot fail. + CreateDebugInfo(shared); + CHECK(PrepareFunctionForBreakPoints(shared)); + } else { + if (!PrepareFunctionForBreakPoints(shared)) return false; + CreateDebugInfo(shared); + } return true; } @@ -1363,7 +1561,7 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) { prev->set_next(current->next()); } delete current; - shared->set_debug_info(isolate_->heap()->undefined_value()); + shared->set_debug_info(DebugInfo::uninitialized()); return; } // Move to next in list. @@ -1374,14 +1572,25 @@ void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) { UNREACHABLE(); } - -void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { - after_break_target_ = NULL; - - if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job. - - // Continue just after the slot. - after_break_target_ = frame->pc(); +Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { + if (frame->is_interpreted()) { + // Find the handler from the original bytecode array. + InterpretedFrame* interpreted_frame = + reinterpret_cast<InterpretedFrame*>(frame); + SharedFunctionInfo* shared = interpreted_frame->function()->shared(); + BytecodeArray* bytecode_array = shared->bytecode_array(); + int bytecode_offset = interpreted_frame->GetBytecodeOffset(); + interpreter::Bytecode bytecode = + interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); + return isolate_->interpreter()->GetBytecodeHandler(bytecode); + } else { + after_break_target_ = NULL; + if (!LiveEdit::SetAfterBreakTarget(this)) { + // Continue just after the slot. + after_break_target_ = frame->pc(); + } + return isolate_->heap()->undefined_value(); + } } @@ -1394,21 +1603,14 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { // With no debug info there are no break points, so we can't be at a return. if (!shared->HasDebugInfo()) return false; - Handle<DebugInfo> debug_info(shared->GetDebugInfo()); - Handle<Code> code(debug_info->code()); -#ifdef DEBUG - // Get the code which is actually executing. - Handle<Code> frame_code(frame->LookupCode()); - DCHECK(frame_code.is_identical_to(code)); -#endif - // Find the reloc info matching the start of the debug break slot. - Address slot_pc = frame->pc() - Assembler::kDebugBreakSlotLength; - int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); - for (RelocIterator it(*code, mask); !it.done(); it.next()) { - if (it.rinfo()->pc() == slot_pc) return true; - } - return false; + DCHECK(!frame->is_optimized()); + FrameSummary summary = GetFirstFrameSummary(frame); + + Handle<DebugInfo> debug_info(shared->GetDebugInfo()); + BreakLocation location = + BreakLocation::FromCodeOffset(debug_info, summary.code_offset()); + return location.IsReturn(); } @@ -1466,16 +1668,18 @@ void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id, Handle<DebugInfo> debug_info(shared->GetDebugInfo()); // Refresh frame summary if the code has been recompiled for debugging. - if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); + if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { + summary = GetFirstFrameSummary(frame); + } - // Find range of break points starting from the break point where execution - // has stopped. - Address call_pc = summary.pc() - 1; + int call_offset = + CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted()); List<BreakLocation> locations; - BreakLocation::FromAddressSameStatement(debug_info, call_pc, &locations); + BreakLocation::FromCodeOffsetSameStatement(debug_info, call_offset, + &locations); for (BreakLocation location : locations) { - if (location.pc() <= summary.pc()) { + if (location.code_offset() <= summary.code_offset()) { // The break point is near our pc. Could be a step-in possibility, // that is currently taken by active debugger call. if (break_frame_id() == StackFrame::NO_ID) { @@ -1619,6 +1823,12 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { if (!break_on_exception_) return; } + { + // Check whether the break location is muted. + JavaScriptFrameIterator it(isolate_); + if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return; + } + DebugScope debug_scope(this); if (debug_scope.failed()) return; @@ -1636,8 +1846,7 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { } -void Debug::OnDebugBreak(Handle<Object> break_points_hit, - bool auto_continue) { +void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { // The caller provided for DebugScope. AssertDebugContext(); // Bail out if there is no listener for this event @@ -2071,6 +2280,8 @@ void Debug::HandleDebugBreak() { JSFunction::cast(fun)->context()->global_object(); // Don't stop in debugger functions. if (IsDebugGlobal(global)) return; + // Don't stop if the break location is muted. + if (IsMutedAtCurrentLocation(it.frame())) return; } } diff --git a/deps/v8/src/debug/debug.h b/deps/v8/src/debug/debug.h index 7dcc2b5e34..81db9e54af 100644 --- a/deps/v8/src/debug/debug.h +++ b/deps/v8/src/debug/debug.h @@ -16,6 +16,7 @@ #include "src/flags.h" #include "src/frames.h" #include "src/hashmap.h" +#include "src/interpreter/source-position-table.h" #include "src/runtime/runtime.h" #include "src/string-stream.h" #include "src/v8threads.h" @@ -64,24 +65,32 @@ class BreakLocation { public: // Find the break point at the supplied address, or the closest one before // the address. - static BreakLocation FromAddress(Handle<DebugInfo> debug_info, Address pc); + static BreakLocation FromCodeOffset(Handle<DebugInfo> debug_info, int offset); - static void FromAddressSameStatement(Handle<DebugInfo> debug_info, Address pc, - List<BreakLocation>* result_out); + static BreakLocation FromFrame(Handle<DebugInfo> debug_info, + JavaScriptFrame* frame); + + static void FromCodeOffsetSameStatement(Handle<DebugInfo> debug_info, + int offset, + List<BreakLocation>* result_out); + + static void AllForStatementPosition(Handle<DebugInfo> debug_info, + int statement_position, + List<BreakLocation>* result_out); static BreakLocation FromPosition(Handle<DebugInfo> debug_info, int position, BreakPositionAlignment alignment); bool IsDebugBreak() const; - inline bool IsReturn() const { - return RelocInfo::IsDebugBreakSlotAtReturn(rmode_); - } - inline bool IsCall() const { - return RelocInfo::IsDebugBreakSlotAtCall(rmode_); + inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } + inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } + inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } + inline bool IsDebuggerStatement() const { + return type_ == DEBUGGER_STATEMENT; } inline bool HasBreakPoint() const { - return debug_info_->HasBreakPoint(pc_offset_); + return debug_info_->HasBreakPoint(code_offset_); } Handle<Object> BreakPointObjects() const; @@ -92,79 +101,118 @@ class BreakLocation { void SetOneShot(); void ClearOneShot(); - - inline RelocInfo rinfo() const { - return RelocInfo(debug_info_->GetIsolate(), pc(), rmode(), data_, code()); - } - inline int position() const { return position_; } inline int statement_position() const { return statement_position_; } - inline Address pc() const { return code()->entry() + pc_offset_; } + inline int code_offset() const { return code_offset_; } + inline Isolate* isolate() { return debug_info_->GetIsolate(); } - inline RelocInfo::Mode rmode() const { return rmode_; } + inline AbstractCode* abstract_code() const { + return debug_info_->abstract_code(); + } - inline Code* code() const { return debug_info_->code(); } + protected: + enum DebugBreakType { + NOT_DEBUG_BREAK, + DEBUGGER_STATEMENT, + DEBUG_BREAK_SLOT, + DEBUG_BREAK_SLOT_AT_CALL, + DEBUG_BREAK_SLOT_AT_RETURN + }; - private: - BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo, int position, - int statement_position); + BreakLocation(Handle<DebugInfo> debug_info, DebugBreakType type, + int code_offset, int position, int statement_position); class Iterator { public: - Iterator(Handle<DebugInfo> debug_info, BreakLocatorType type); - - BreakLocation GetBreakLocation() { - return BreakLocation(debug_info_, rinfo(), position(), - statement_position()); - } + virtual ~Iterator() {} - inline bool Done() const { return reloc_iterator_.done(); } - void Next(); + virtual BreakLocation GetBreakLocation() = 0; + virtual bool Done() const = 0; + virtual void Next() = 0; void SkipTo(int count) { while (count-- > 0) Next(); } - inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); } - inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); } - inline Address pc() { return rinfo()->pc(); } + virtual int code_offset() = 0; int break_index() const { return break_index_; } inline int position() const { return position_; } inline int statement_position() const { return statement_position_; } - private: - static int GetModeMask(BreakLocatorType type); + protected: + explicit Iterator(Handle<DebugInfo> debug_info); Handle<DebugInfo> debug_info_; - RelocIterator reloc_iterator_; int break_index_; int position_; int statement_position_; + private: DisallowHeapAllocation no_gc_; - DISALLOW_COPY_AND_ASSIGN(Iterator); }; + class CodeIterator : public Iterator { + public: + CodeIterator(Handle<DebugInfo> debug_info, BreakLocatorType type); + ~CodeIterator() override {} + + BreakLocation GetBreakLocation() override; + bool Done() const override { return reloc_iterator_.done(); } + void Next() override; + + int code_offset() override { + return static_cast<int>( + rinfo()->pc() - + debug_info_->abstract_code()->GetCode()->instruction_start()); + } + + private: + static int GetModeMask(BreakLocatorType type); + RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); } + RelocInfo* rinfo() { return reloc_iterator_.rinfo(); } + + RelocIterator reloc_iterator_; + DISALLOW_COPY_AND_ASSIGN(CodeIterator); + }; + + class BytecodeArrayIterator : public Iterator { + public: + BytecodeArrayIterator(Handle<DebugInfo> debug_info, BreakLocatorType type); + ~BytecodeArrayIterator() override {} + + BreakLocation GetBreakLocation() override; + bool Done() const override { return source_position_iterator_.done(); } + void Next() override; + + int code_offset() override { + return source_position_iterator_.bytecode_offset(); + } + + private: + DebugBreakType GetDebugBreakType(); + + interpreter::SourcePositionTableIterator source_position_iterator_; + BreakLocatorType break_locator_type_; + int start_position_; + DISALLOW_COPY_AND_ASSIGN(BytecodeArrayIterator); + }; + + static Iterator* GetIterator(Handle<DebugInfo> debug_info, + BreakLocatorType type = ALL_BREAK_LOCATIONS); + + private: friend class Debug; - static int BreakIndexFromAddress(Handle<DebugInfo> debug_info, Address pc); + static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, int offset); void SetDebugBreak(); void ClearDebugBreak(); - inline bool IsDebuggerStatement() const { - return RelocInfo::IsDebuggerStatement(rmode_); - } - inline bool IsDebugBreakSlot() const { - return RelocInfo::IsDebugBreakSlot(rmode_); - } - Handle<DebugInfo> debug_info_; - int pc_offset_; - RelocInfo::Mode rmode_; - intptr_t data_; + int code_offset_; + DebugBreakType type_; int position_; int statement_position_; }; @@ -383,7 +431,7 @@ class Debug { // Internal logic bool Load(); void Break(Arguments args, JavaScriptFrame*); - void SetAfterBreakTarget(JavaScriptFrame* frame); + Object* SetAfterBreakTarget(JavaScriptFrame* frame); // Scripts handling. Handle<FixedArray> GetLoadedScripts(); @@ -555,7 +603,9 @@ class Debug { void ClearOneShot(); void ActivateStepOut(StackFrame* frame); void RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info); - Handle<Object> CheckBreakPoints(Handle<Object> break_point); + Handle<Object> CheckBreakPoints(BreakLocation* location, + bool* has_break_points = nullptr); + bool IsMutedAtCurrentLocation(JavaScriptFrame* frame); bool CheckBreakPoint(Handle<Object> break_point_object); MaybeHandle<Object> CallFunction(const char* name, int argc, Handle<Object> args[]); @@ -739,6 +789,7 @@ class DebugCodegen : public AllStatic { static void PatchDebugBreakSlot(Isolate* isolate, Address pc, Handle<Code> code); + static bool DebugBreakSlotIsPatched(Address pc); static void ClearDebugBreakSlot(Isolate* isolate, Address pc); }; diff --git a/deps/v8/src/debug/debug.js b/deps/v8/src/debug/debug.js index 1158f7dd38..6849bf5345 100644 --- a/deps/v8/src/debug/debug.js +++ b/deps/v8/src/debug/debug.js @@ -147,10 +147,8 @@ function BreakPoint(source_position, opt_script_break_point) { } else { this.number_ = next_break_point_number++; } - this.hit_count_ = 0; this.active_ = true; this.condition_ = null; - this.ignoreCount_ = 0; } @@ -169,11 +167,6 @@ BreakPoint.prototype.source_position = function() { }; -BreakPoint.prototype.hit_count = function() { - return this.hit_count_; -}; - - BreakPoint.prototype.active = function() { if (this.script_break_point()) { return this.script_break_point().active(); @@ -190,11 +183,6 @@ BreakPoint.prototype.condition = function() { }; -BreakPoint.prototype.ignoreCount = function() { - return this.ignoreCount_; -}; - - BreakPoint.prototype.script_break_point = function() { return this.script_break_point_; }; @@ -215,11 +203,6 @@ BreakPoint.prototype.setCondition = function(condition) { }; -BreakPoint.prototype.setIgnoreCount = function(ignoreCount) { - this.ignoreCount_ = ignoreCount; -}; - - BreakPoint.prototype.isTriggered = function(exec_state) { // Break point not active - not triggered. if (!this.active()) return false; @@ -239,18 +222,6 @@ BreakPoint.prototype.isTriggered = function(exec_state) { } } - // Update the hit count. - this.hit_count_++; - if (this.script_break_point_) { - this.script_break_point_.hit_count_++; - } - - // If the break point has an ignore count it is not triggered. - if (this.ignoreCount_ > 0) { - this.ignoreCount_--; - return false; - } - // Break point triggered. return true; }; @@ -283,10 +254,8 @@ function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column, this.groupId_ = opt_groupId; this.position_alignment_ = IS_UNDEFINED(opt_position_alignment) ? Debug.BreakPositionAlignment.Statement : opt_position_alignment; - this.hit_count_ = 0; this.active_ = true; this.condition_ = null; - this.ignoreCount_ = 0; this.break_points_ = []; } @@ -299,10 +268,8 @@ ScriptBreakPoint.prototype.cloneForOtherScript = function (other_script) { copy.number_ = next_break_point_number++; script_break_points.push(copy); - copy.hit_count_ = this.hit_count_; copy.active_ = this.active_; copy.condition_ = this.condition_; - copy.ignoreCount_ = this.ignoreCount_; return copy; }; @@ -362,11 +329,6 @@ ScriptBreakPoint.prototype.update_positions = function(line, column) { }; -ScriptBreakPoint.prototype.hit_count = function() { - return this.hit_count_; -}; - - ScriptBreakPoint.prototype.active = function() { return this.active_; }; @@ -377,11 +339,6 @@ ScriptBreakPoint.prototype.condition = function() { }; -ScriptBreakPoint.prototype.ignoreCount = function() { - return this.ignoreCount_; -}; - - ScriptBreakPoint.prototype.enable = function() { this.active_ = true; }; @@ -397,16 +354,6 @@ ScriptBreakPoint.prototype.setCondition = function(condition) { }; -ScriptBreakPoint.prototype.setIgnoreCount = function(ignoreCount) { - this.ignoreCount_ = ignoreCount; - - // Set ignore count on all break points created from this script break point. - for (var i = 0; i < this.break_points_.length; i++) { - this.break_points_[i].setIgnoreCount(ignoreCount); - } -}; - - // Check whether a script matches this script break point. Currently this is // only based on script name. ScriptBreakPoint.prototype.matchesScript = function(script) { @@ -461,7 +408,6 @@ ScriptBreakPoint.prototype.set = function (script) { // Create a break point object and set the break point. var break_point = MakeBreakPoint(position, this); - break_point.setIgnoreCount(this.ignoreCount()); var actual_position = %SetScriptBreakPoint(script, position, this.position_alignment_, break_point); @@ -726,13 +672,6 @@ Debug.changeBreakPointCondition = function(break_point_number, condition) { }; -Debug.changeBreakPointIgnoreCount = function(break_point_number, ignoreCount) { - if (ignoreCount < 0) throw MakeError(kDebugger, 'Invalid argument'); - var break_point = this.findBreakPoint(break_point_number, false); - break_point.setIgnoreCount(ignoreCount); -}; - - Debug.clearBreakPoint = function(break_point_number) { var break_point = this.findBreakPoint(break_point_number, true); if (break_point) { @@ -857,14 +796,6 @@ Debug.changeScriptBreakPointCondition = function( }; -Debug.changeScriptBreakPointIgnoreCount = function( - break_point_number, ignoreCount) { - if (ignoreCount < 0) throw MakeError(kDebugger, 'Invalid argument'); - var script_break_point = this.findScriptBreakPoint(break_point_number, false); - script_break_point.setIgnoreCount(ignoreCount); -}; - - Debug.scriptBreakPoints = function() { return script_break_points; }; @@ -1503,7 +1434,6 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = var enabled = IS_UNDEFINED(request.arguments.enabled) ? true : request.arguments.enabled; var condition = request.arguments.condition; - var ignoreCount = request.arguments.ignoreCount; var groupId = request.arguments.groupId; // Check for legal arguments. @@ -1569,9 +1499,6 @@ DebugCommandProcessor.prototype.setBreakPointRequest_ = // Set additional break point properties. var break_point = Debug.findBreakPoint(break_point_number); - if (ignoreCount) { - Debug.changeBreakPointIgnoreCount(break_point_number, ignoreCount); - } if (!enabled) { Debug.disableBreakPoint(break_point_number); } @@ -1617,7 +1544,6 @@ DebugCommandProcessor.prototype.changeBreakPointRequest_ = function( var break_point = TO_NUMBER(request.arguments.breakpoint); var enabled = request.arguments.enabled; var condition = request.arguments.condition; - var ignoreCount = request.arguments.ignoreCount; // Check for legal arguments. if (!break_point) { @@ -1638,11 +1564,6 @@ DebugCommandProcessor.prototype.changeBreakPointRequest_ = function( if (!IS_UNDEFINED(condition)) { Debug.changeBreakPointCondition(break_point, condition); } - - // Change ignore count if supplied - if (!IS_UNDEFINED(ignoreCount)) { - Debug.changeBreakPointIgnoreCount(break_point, ignoreCount); - } }; @@ -1717,10 +1638,8 @@ DebugCommandProcessor.prototype.listBreakpointsRequest_ = function( line: break_point.line(), column: break_point.column(), groupId: break_point.groupId(), - hit_count: break_point.hit_count(), active: break_point.active(), condition: break_point.condition(), - ignoreCount: break_point.ignoreCount(), actual_locations: break_point.actual_locations() }; diff --git a/deps/v8/src/debug/ia32/debug-ia32.cc b/deps/v8/src/debug/ia32/debug-ia32.cc index d489a01441..95f2bc6b68 100644 --- a/deps/v8/src/debug/ia32/debug-ia32.cc +++ b/deps/v8/src/debug/ia32/debug-ia32.cc @@ -50,6 +50,9 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + return !Assembler::IsNop(pc); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/liveedit.cc b/deps/v8/src/debug/liveedit.cc index f1f3f2391a..91c990d19b 100644 --- a/deps/v8/src/debug/liveedit.cc +++ b/deps/v8/src/debug/liveedit.cc @@ -1857,8 +1857,8 @@ bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array, HandleScope scope(isolate); for (int i = 0; i < len; i++) { - Handle<JSValue> jsvalue = - Handle<JSValue>::cast(FixedArray::get(shared_info_array, i)); + Handle<JSValue> jsvalue = Handle<JSValue>::cast( + FixedArray::get(*shared_info_array, i, isolate)); Handle<SharedFunctionInfo> shared = UnwrapSharedFunctionInfoFromJSValue(jsvalue); diff --git a/deps/v8/src/debug/mips/debug-mips.cc b/deps/v8/src/debug/mips/debug-mips.cc index c5c58d044b..1d9f7d6037 100644 --- a/deps/v8/src/debug/mips/debug-mips.cc +++ b/deps/v8/src/debug/mips/debug-mips.cc @@ -56,6 +56,10 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, patcher.masm()->Call(v8::internal::t9); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + Instr current_instr = Assembler::instr_at(pc); + return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/mips64/debug-mips64.cc b/deps/v8/src/debug/mips64/debug-mips64.cc index 1d65fd9efd..0646a249f7 100644 --- a/deps/v8/src/debug/mips64/debug-mips64.cc +++ b/deps/v8/src/debug/mips64/debug-mips64.cc @@ -58,6 +58,10 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, patcher.masm()->Call(v8::internal::t9); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + Instr current_instr = Assembler::instr_at(pc); + return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/mirrors.js b/deps/v8/src/debug/mirrors.js index 1fd5fa9ecd..8b9dd02b6e 100644 --- a/deps/v8/src/debug/mirrors.js +++ b/deps/v8/src/debug/mirrors.js @@ -812,7 +812,7 @@ ObjectMirror.prototype.lookupProperty = function(value) { // Skip properties which are defined through accessors. var property = properties[i]; if (property.propertyType() != PropertyType.AccessorConstant) { - if (%_ObjectEquals(property.value_, value.value_)) { + if (property.value_ === value.value_) { return property; } } diff --git a/deps/v8/src/debug/ppc/debug-ppc.cc b/deps/v8/src/debug/ppc/debug-ppc.cc index c5ddab8bc0..aab5399fee 100644 --- a/deps/v8/src/debug/ppc/debug-ppc.cc +++ b/deps/v8/src/debug/ppc/debug-ppc.cc @@ -64,6 +64,10 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, patcher.masm()->bctrl(); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + Instr current_instr = Assembler::instr_at(pc); + return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/x64/debug-x64.cc b/deps/v8/src/debug/x64/debug-x64.cc index 0d56ea7521..f7fbe7691e 100644 --- a/deps/v8/src/debug/x64/debug-x64.cc +++ b/deps/v8/src/debug/x64/debug-x64.cc @@ -51,6 +51,9 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + return !Assembler::IsNop(pc); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { diff --git a/deps/v8/src/debug/x87/debug-x87.cc b/deps/v8/src/debug/x87/debug-x87.cc index 8c04e02b89..8ddb82f39d 100644 --- a/deps/v8/src/debug/x87/debug-x87.cc +++ b/deps/v8/src/debug/x87/debug-x87.cc @@ -50,6 +50,9 @@ void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); } +bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { + return !Assembler::IsNop(pc); +} void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, DebugBreakCallHelperMode mode) { |