summaryrefslogtreecommitdiff
path: root/deps/v8/src/debug
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/debug')
-rw-r--r--deps/v8/src/debug/arm/debug-arm.cc4
-rw-r--r--deps/v8/src/debug/arm64/debug-arm64.cc4
-rw-r--r--deps/v8/src/debug/debug-evaluate.cc7
-rw-r--r--deps/v8/src/debug/debug-frames.cc51
-rw-r--r--deps/v8/src/debug/debug-frames.h9
-rw-r--r--deps/v8/src/debug/debug-scopes.cc26
-rw-r--r--deps/v8/src/debug/debug-scopes.h5
-rw-r--r--deps/v8/src/debug/debug.cc519
-rw-r--r--deps/v8/src/debug/debug.h147
-rw-r--r--deps/v8/src/debug/debug.js81
-rw-r--r--deps/v8/src/debug/ia32/debug-ia32.cc3
-rw-r--r--deps/v8/src/debug/liveedit.cc4
-rw-r--r--deps/v8/src/debug/mips/debug-mips.cc4
-rw-r--r--deps/v8/src/debug/mips64/debug-mips64.cc4
-rw-r--r--deps/v8/src/debug/mirrors.js2
-rw-r--r--deps/v8/src/debug/ppc/debug-ppc.cc4
-rw-r--r--deps/v8/src/debug/x64/debug-x64.cc3
-rw-r--r--deps/v8/src/debug/x87/debug-x87.cc3
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) {