summaryrefslogtreecommitdiff
path: root/deps/v8/src/debug/debug.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/debug/debug.cc')
-rw-r--r--deps/v8/src/debug/debug.cc387
1 files changed, 194 insertions, 193 deletions
diff --git a/deps/v8/src/debug/debug.cc b/deps/v8/src/debug/debug.cc
index c087a0868c..69eaeb6cad 100644
--- a/deps/v8/src/debug/debug.cc
+++ b/deps/v8/src/debug/debug.cc
@@ -12,7 +12,6 @@
#include "src/bootstrapper.h"
#include "src/code-stubs.h"
#include "src/compilation-cache.h"
-#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
#include "src/compiler.h"
#include "src/debug/debug-evaluate.h"
#include "src/debug/liveedit.h"
@@ -21,6 +20,7 @@
#include "src/frames-inl.h"
#include "src/global-handles.h"
#include "src/globals.h"
+#include "src/interpreter/bytecode-array-accessor.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h"
#include "src/log.h"
@@ -29,8 +29,6 @@
#include "src/snapshot/natives.h"
#include "src/wasm/wasm-objects-inl.h"
-#include "include/v8-debug.h"
-
namespace v8 {
namespace internal {
@@ -53,6 +51,9 @@ Debug::Debug(Isolate* isolate)
BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
JavaScriptFrame* frame) {
+ if (debug_info->CanBreakAtEntry()) {
+ return BreakLocation(Debug::kBreakAtEntryPosition, DEBUG_BREAK_AT_ENTRY);
+ }
auto summary = FrameSummary::GetTop(frame).AsJavaScript();
int offset = summary.code_offset();
Handle<AbstractCode> abstract_code = summary.abstract_code();
@@ -64,6 +65,7 @@ BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
void BreakLocation::AllAtCurrentStatement(
Handle<DebugInfo> debug_info, JavaScriptFrame* frame,
std::vector<BreakLocation>* result_out) {
+ DCHECK(!debug_info->CanBreakAtEntry());
auto summary = FrameSummary::GetTop(frame).AsJavaScript();
int offset = summary.code_offset();
Handle<AbstractCode> abstract_code = summary.abstract_code();
@@ -81,6 +83,18 @@ void BreakLocation::AllAtCurrentStatement(
}
}
+JSGeneratorObject* BreakLocation::GetGeneratorObjectForSuspendedFrame(
+ JavaScriptFrame* frame) const {
+ DCHECK(IsSuspend());
+ DCHECK_GE(generator_obj_reg_index_, 0);
+
+ Object* generator_obj =
+ InterpretedFrame::cast(frame)->ReadInterpreterRegister(
+ generator_obj_reg_index_);
+
+ return JSGeneratorObject::cast(generator_obj);
+}
+
int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
Handle<AbstractCode> abstract_code,
int offset) {
@@ -103,13 +117,18 @@ int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const {
// First check whether there is a break point with the same source position.
if (!debug_info->HasBreakPoint(position_)) return false;
- // Then check whether a break point at that source position would have
- // the same code offset. Otherwise it's just a break location that we can
- // step to, but not actually a location where we can put a break point.
- DCHECK(abstract_code_->IsBytecodeArray());
- BreakIterator it(debug_info);
- it.SkipToPosition(position_);
- return it.code_offset() == code_offset_;
+ if (debug_info->CanBreakAtEntry()) {
+ DCHECK_EQ(Debug::kBreakAtEntryPosition, position_);
+ return debug_info->BreakAtEntry();
+ } else {
+ // Then check whether a break point at that source position would have
+ // the same code offset. Otherwise it's just a break location that we can
+ // step to, but not actually a location where we can put a break point.
+ DCHECK(abstract_code_->IsBytecodeArray());
+ BreakIterator it(debug_info);
+ it.SkipToPosition(position_);
+ return it.code_offset() == code_offset_;
+ }
}
debug::BreakLocationType BreakLocation::type() const {
@@ -120,10 +139,12 @@ debug::BreakLocationType BreakLocation::type() const {
return debug::kCallBreakLocation;
case DEBUG_BREAK_SLOT_AT_RETURN:
return debug::kReturnBreakLocation;
+
+ // Externally, suspend breaks should look like normal breaks.
+ case DEBUG_BREAK_SLOT_AT_SUSPEND:
default:
return debug::kCommonBreakLocation;
}
- return debug::kCommonBreakLocation;
}
BreakIterator::BreakIterator(Handle<DebugInfo> debug_info)
@@ -181,10 +202,18 @@ DebugBreakType BreakIterator::GetDebugBreakType() {
interpreter::Bytecode bytecode =
interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
+ // Make sure we read the actual bytecode, not a prefix scaling bytecode.
+ if (interpreter::Bytecodes::IsPrefixScalingBytecode(bytecode)) {
+ bytecode = interpreter::Bytecodes::FromByte(
+ bytecode_array->get(code_offset() + 1));
+ }
+
if (bytecode == interpreter::Bytecode::kDebugger) {
return DEBUGGER_STATEMENT;
} else if (bytecode == interpreter::Bytecode::kReturn) {
return DEBUG_BREAK_SLOT_AT_RETURN;
+ } else if (bytecode == interpreter::Bytecode::kSuspendGenerator) {
+ return DEBUG_BREAK_SLOT_AT_SUSPEND;
} else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
return DEBUG_BREAK_SLOT_AT_CALL;
} else if (source_position_iterator_.is_statement()) {
@@ -225,7 +254,25 @@ void BreakIterator::ClearDebugBreak() {
BreakLocation BreakIterator::GetBreakLocation() {
Handle<AbstractCode> code(
AbstractCode::cast(debug_info_->DebugBytecodeArray()));
- return BreakLocation(code, GetDebugBreakType(), code_offset(), position_);
+ DebugBreakType type = GetDebugBreakType();
+ int generator_object_reg_index = -1;
+ if (type == DEBUG_BREAK_SLOT_AT_SUSPEND) {
+ // For suspend break, we'll need the generator object to be able to step
+ // over the suspend as if it didn't return. We get the interpreter register
+ // index that holds the generator object by reading it directly off the
+ // bytecode array, and we'll read the actual generator object off the
+ // interpreter stack frame in GetGeneratorObjectForSuspendedFrame.
+ BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray();
+ interpreter::BytecodeArrayAccessor accessor(handle(bytecode_array),
+ code_offset());
+
+ DCHECK_EQ(accessor.current_bytecode(),
+ interpreter::Bytecode::kSuspendGenerator);
+ interpreter::Register generator_obj_reg = accessor.GetRegisterOperand(0);
+ generator_object_reg_index = generator_obj_reg.index();
+ }
+ return BreakLocation(code, type, code_offset(), position_,
+ generator_object_reg_index);
}
@@ -276,9 +323,11 @@ char* Debug::RestoreDebug(char* storage) {
int Debug::ArchiveSpacePerThread() { return 0; }
void Debug::Iterate(RootVisitor* v) {
- v->VisitRootPointer(Root::kDebug, &thread_local_.return_value_);
- v->VisitRootPointer(Root::kDebug, &thread_local_.suspended_generator_);
- v->VisitRootPointer(Root::kDebug, &thread_local_.ignore_step_into_function_);
+ v->VisitRootPointer(Root::kDebug, nullptr, &thread_local_.return_value_);
+ v->VisitRootPointer(Root::kDebug, nullptr,
+ &thread_local_.suspended_generator_);
+ v->VisitRootPointer(Root::kDebug, nullptr,
+ &thread_local_.ignore_step_into_function_);
}
DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info) : next_(nullptr) {
@@ -346,7 +395,7 @@ void Debug::Unload() {
debug_context_ = Handle<Context>();
}
-void Debug::Break(JavaScriptFrame* frame) {
+void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) {
// Initialize LiveEdit.
LiveEdit::InitializeThreadLocal(this);
@@ -362,8 +411,7 @@ void Debug::Break(JavaScriptFrame* frame) {
DisableBreak no_recursive_break(this);
// Return if we fail to retrieve debug info.
- Handle<JSFunction> function(frame->function());
- Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<SharedFunctionInfo> shared(break_target->shared());
if (!EnsureBreakInfo(shared)) return;
Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
@@ -381,6 +429,14 @@ void Debug::Break(JavaScriptFrame* frame) {
return;
}
+ // Debug break at function entry, do not worry about stepping.
+ if (location.IsDebugBreakAtEntry()) {
+ DCHECK(debug_info->BreakAtEntry());
+ return;
+ }
+
+ DCHECK_NOT_NULL(frame);
+
// No break point. Check for stepping.
StepAction step_action = last_step_action();
int current_frame_count = CurrentFrameCount();
@@ -390,7 +446,7 @@ void Debug::Break(JavaScriptFrame* frame) {
// StepOut at not return position was requested and return break locations
// were flooded with one shots.
if (thread_local_.fast_forward_to_return_) {
- DCHECK(location.IsReturn());
+ DCHECK(location.IsReturnOrSuspend());
// We have to ignore recursive calls to function.
if (current_frame_count > target_frame_count) return;
ClearStepping();
@@ -410,8 +466,17 @@ void Debug::Break(JavaScriptFrame* frame) {
case StepNext:
// Step next should not break in a deeper frame than target frame.
if (current_frame_count > target_frame_count) return;
- // Fall through.
+ V8_FALLTHROUGH;
case StepIn: {
+ // Special case "next" and "in" for generators that are about to suspend.
+ if (location.IsSuspend()) {
+ DCHECK(!has_suspended_generator());
+ thread_local_.suspended_generator_ =
+ location.GetGeneratorObjectForSuspendedFrame(frame);
+ ClearStepping();
+ return;
+ }
+
FrameSummary summary = FrameSummary::GetTop(frame);
step_break = step_break || location.IsReturn() ||
current_frame_count != last_frame_count ||
@@ -445,9 +510,9 @@ MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info,
if (has_break_points) *has_break_points = has_break_points_to_check;
if (!has_break_points_to_check) return {};
- Handle<Object> break_point_objects =
- debug_info->GetBreakPointObjects(location->position());
- return Debug::GetHitBreakPointObjects(break_point_objects);
+ Handle<Object> break_points =
+ debug_info->GetBreakPoints(location->position());
+ return Debug::GetHitBreakPoints(break_points);
}
@@ -502,52 +567,27 @@ MaybeHandle<Object> Debug::CallFunction(const char* name, int argc,
// Check whether a single break point object is triggered.
-bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
- Factory* factory = isolate_->factory();
+bool Debug::CheckBreakPoint(Handle<BreakPoint> break_point) {
HandleScope scope(isolate_);
- // TODO(kozyatinskiy): replace this if by DCHEK once the JS debug API has been
- // removed.
- if (break_point_object->IsBreakPoint()) {
- Handle<BreakPoint> break_point =
- Handle<BreakPoint>::cast(break_point_object);
- if (!break_point->condition()->length()) return true;
- Handle<String> condition(break_point->condition());
- Handle<Object> result;
- // Since we call CheckBreakpoint only for deoptimized frame on top of stack,
- // we can use 0 as index of inlined frame.
- if (!DebugEvaluate::Local(isolate_, break_frame_id(),
- /* inlined_jsframe_index */ 0, condition, false)
- .ToHandle(&result)) {
- if (isolate_->has_pending_exception()) {
- isolate_->clear_pending_exception();
- }
- return false;
- }
- return result->BooleanValue();
- }
-
- // Ignore check if break point object is not a JSObject.
- if (!break_point_object->IsJSObject()) return true;
-
- // Get the break id as an object.
- Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
-
- // Call IsBreakPointTriggered.
- Handle<Object> argv[] = { break_id, break_point_object };
+ if (!break_point->condition()->length()) return true;
+ Handle<String> condition(break_point->condition());
Handle<Object> result;
- if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv)
+ // Since we call CheckBreakpoint only for deoptimized frame on top of stack,
+ // we can use 0 as index of inlined frame.
+ if (!DebugEvaluate::Local(isolate_, break_frame_id(),
+ /* inlined_jsframe_index */ 0, condition, false)
.ToHandle(&result)) {
+ if (isolate_->has_pending_exception()) {
+ isolate_->clear_pending_exception();
+ }
return false;
}
-
- // Return whether the break point is triggered.
- return result->IsTrue(isolate_);
+ return result->BooleanValue();
}
-
bool Debug::SetBreakPoint(Handle<JSFunction> function,
- Handle<Object> break_point_object,
+ Handle<BreakPoint> break_point,
int* source_position) {
HandleScope scope(isolate_);
@@ -561,7 +601,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
// Find the break point and change it.
*source_position = FindBreakablePosition(debug_info, *source_position);
- DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
+ DebugInfo::SetBreakPoint(debug_info, *source_position, break_point);
// At least one active break point now.
DCHECK_LT(0, debug_info->GetBreakPointCount());
@@ -573,13 +613,13 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
}
bool Debug::SetBreakPointForScript(Handle<Script> script,
- Handle<Object> break_point_object,
+ Handle<BreakPoint> break_point,
int* source_position) {
if (script->type() == Script::TYPE_WASM) {
Handle<WasmCompiledModule> compiled_module(
WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
return WasmCompiledModule::SetBreakPoint(compiled_module, source_position,
- break_point_object);
+ break_point);
}
HandleScope scope(isolate_);
@@ -609,7 +649,7 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
if (breakable_position < *source_position) return false;
*source_position = breakable_position;
- DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
+ DebugInfo::SetBreakPoint(debug_info, *source_position, break_point);
// At least one active break point now.
DCHECK_LT(0, debug_info->GetBreakPointCount());
@@ -622,48 +662,60 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info,
int source_position) {
- DCHECK(debug_info->HasDebugBytecodeArray());
- BreakIterator it(debug_info);
- it.SkipToPosition(source_position);
- return it.position();
+ if (debug_info->CanBreakAtEntry()) {
+ return kBreakAtEntryPosition;
+ } else {
+ DCHECK(debug_info->HasDebugBytecodeArray());
+ BreakIterator it(debug_info);
+ it.SkipToPosition(source_position);
+ return it.position();
+ }
}
void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) {
DisallowHeapAllocation no_gc;
- if (debug_info->break_points()->IsUndefined(isolate_)) return;
- FixedArray* break_points = debug_info->break_points();
- for (int i = 0; i < break_points->length(); i++) {
- if (break_points->get(i)->IsUndefined(isolate_)) continue;
- BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i));
- if (info->GetBreakPointCount() == 0) continue;
- DCHECK(debug_info->HasDebugBytecodeArray());
- BreakIterator it(debug_info);
- it.SkipToPosition(info->source_position());
- it.SetDebugBreak();
+ if (debug_info->CanBreakAtEntry()) {
+ debug_info->SetBreakAtEntry();
+ } else {
+ if (!debug_info->HasDebugBytecodeArray()) return;
+ FixedArray* break_points = debug_info->break_points();
+ for (int i = 0; i < break_points->length(); i++) {
+ if (break_points->get(i)->IsUndefined(isolate_)) continue;
+ BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i));
+ if (info->GetBreakPointCount() == 0) continue;
+ DCHECK(debug_info->HasDebugBytecodeArray());
+ BreakIterator it(debug_info);
+ it.SkipToPosition(info->source_position());
+ it.SetDebugBreak();
+ }
}
}
void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) {
- // If we attempt to clear breakpoints but none exist, simply return. This can
- // happen e.g. CoverageInfos exit but no breakpoints are set.
- if (!debug_info->HasDebugBytecodeArray()) return;
+ if (debug_info->CanBreakAtEntry()) {
+ debug_info->ClearBreakAtEntry();
+ } else {
+ // If we attempt to clear breakpoints but none exist, simply return. This
+ // can happen e.g. CoverageInfos exist but no breakpoints are set.
+ if (!debug_info->HasDebugBytecodeArray()) return;
- DisallowHeapAllocation no_gc;
- for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
- it.ClearDebugBreak();
+ DisallowHeapAllocation no_gc;
+ for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
+ it.ClearDebugBreak();
+ }
}
}
-void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
+void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) {
HandleScope scope(isolate_);
for (DebugInfoListNode* node = debug_info_list_; node != nullptr;
node = node->next()) {
Handle<Object> result =
- DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
+ DebugInfo::FindBreakPointInfo(node->debug_info(), break_point);
if (result->IsUndefined(isolate_)) continue;
Handle<DebugInfo> debug_info = node->debug_info();
- if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) {
+ if (DebugInfo::ClearBreakPoint(debug_info, break_point)) {
ClearBreakPoints(debug_info);
if (debug_info->GetBreakPointCount() == 0) {
RemoveBreakInfoAndMaybeFree(debug_info);
@@ -707,7 +759,7 @@ void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared,
// Flood the function with break points.
DCHECK(debug_info->HasDebugBytecodeArray());
for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
- if (returns_only && !it.GetBreakLocation().IsReturn()) continue;
+ if (returns_only && !it.GetBreakLocation().IsReturnOrSuspend()) continue;
it.SetDebugBreak();
}
}
@@ -729,25 +781,24 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) {
}
}
-MaybeHandle<FixedArray> Debug::GetHitBreakPointObjects(
- Handle<Object> break_point_objects) {
- DCHECK(!break_point_objects->IsUndefined(isolate_));
- if (!break_point_objects->IsFixedArray()) {
- if (!CheckBreakPoint(break_point_objects)) return {};
+MaybeHandle<FixedArray> Debug::GetHitBreakPoints(Handle<Object> break_points) {
+ DCHECK(!break_points->IsUndefined(isolate_));
+ if (!break_points->IsFixedArray()) {
+ if (!CheckBreakPoint(Handle<BreakPoint>::cast(break_points))) return {};
Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1);
- break_points_hit->set(0, *break_point_objects);
+ break_points_hit->set(0, *break_points);
return break_points_hit;
}
- Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
+ Handle<FixedArray> array(FixedArray::cast(*break_points));
int num_objects = array->length();
Handle<FixedArray> break_points_hit =
isolate_->factory()->NewFixedArray(num_objects);
int break_points_hit_count = 0;
for (int i = 0; i < num_objects; ++i) {
- 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);
+ Handle<Object> break_point(array->get(i), isolate_);
+ if (CheckBreakPoint(Handle<BreakPoint>::cast(break_point))) {
+ break_points_hit->set(break_points_hit_count++, *break_point);
}
}
if (break_points_hit_count == 0) return {};
@@ -824,11 +875,10 @@ void Debug::PrepareStepOnThrow() {
if (summaries.size() > 1) {
Handle<AbstractCode> code = summary.AsJavaScript().abstract_code();
CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind());
- BytecodeArray* bytecode = code->GetBytecodeArray();
- HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
+ HandlerTable table(code->GetBytecodeArray());
int code_offset = summary.code_offset();
HandlerTable::CatchPrediction prediction;
- int index = table->LookupRange(code_offset, nullptr, &prediction);
+ int index = table.LookupRange(code_offset, nullptr, &prediction);
if (index > 0) found_handler = true;
} else {
found_handler = true;
@@ -879,7 +929,7 @@ void Debug::PrepareStep(StepAction step_action) {
if (frame->is_wasm_compiled()) return;
WasmInterpreterEntryFrame* wasm_frame =
WasmInterpreterEntryFrame::cast(frame);
- wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action);
+ wasm_frame->debug_info()->PrepareStep(step_action);
return;
}
@@ -895,9 +945,9 @@ void Debug::PrepareStep(StepAction step_action) {
BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame);
- // Any step at a return is a step-out and we need to schedule DebugOnFunction
- // call callback.
- if (location.IsReturn()) {
+ // Any step at a return is a step-out, and a step-out at a suspend behaves
+ // like a return.
+ if (location.IsReturn() || (location.IsSuspend() && step_action == StepOut)) {
// On StepOut we'll ignore our further calls to current function in
// PrepareStepIn callback.
if (last_step_action() == StepOut) {
@@ -906,6 +956,8 @@ void Debug::PrepareStep(StepAction step_action) {
step_action = StepOut;
thread_local_.last_step_action_ = StepIn;
}
+
+ // We need to schedule DebugOnFunction call callback
UpdateHookOnFunctionCall();
// A step-next in blackboxed function is a step-out.
@@ -926,7 +978,7 @@ void Debug::PrepareStep(StepAction step_action) {
// Clear last position info. For stepping out it does not matter.
thread_local_.last_statement_position_ = kNoSourcePosition;
thread_local_.last_frame_count_ = -1;
- if (!location.IsReturn() && !IsBlackboxed(shared)) {
+ if (!location.IsReturnOrSuspend() && !IsBlackboxed(shared)) {
// At not return position we flood return positions with one shots and
// will repeat StepOut automatically at next break.
thread_local_.target_frame_count_ = current_frame_count;
@@ -966,7 +1018,7 @@ void Debug::PrepareStep(StepAction step_action) {
}
case StepNext:
thread_local_.target_frame_count_ = current_frame_count;
- // Fall through.
+ V8_FALLTHROUGH;
case StepIn:
// TODO(clemensh): Implement stepping from JS into wasm.
FloodWithOneShot(shared);
@@ -1060,10 +1112,7 @@ class RedirectActiveFunctions : public ThreadVisitor {
void Debug::DeoptimizeFunction(Handle<SharedFunctionInfo> shared) {
// Deoptimize all code compiled from this shared function info including
// inlining.
- if (isolate_->concurrent_recompilation_enabled()) {
- isolate_->optimizing_compile_dispatcher()->Flush(
- OptimizingCompileDispatcher::BlockingBehavior::kBlock);
- }
+ isolate_->AbortConcurrentOptimization(BlockingBehavior::kBlock);
// Make sure we abort incremental marking.
isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
@@ -1094,11 +1143,16 @@ void Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
if (debug_info->IsPreparedForBreakpoints()) return;
- DeoptimizeFunction(shared);
- // Update PCs on the stack to point to recompiled code.
- RedirectActiveFunctions redirect_visitor(*shared);
- redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
- isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
+ if (debug_info->CanBreakAtEntry()) {
+ // Deopt everything in case the function is inlined anywhere.
+ Deoptimizer::DeoptimizeAll(isolate_);
+ } else {
+ DeoptimizeFunction(shared);
+ // Update PCs on the stack to point to recompiled code.
+ RedirectActiveFunctions redirect_visitor(*shared);
+ redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
+ isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
+ }
debug_info->set_flags(debug_info->flags() |
DebugInfo::kPreparedForBreakpoints);
@@ -1184,19 +1238,6 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
UNREACHABLE();
}
-void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) {
- if (last_step_action() <= StepOut) return;
-
- if (last_step_action() == StepNext) {
- // Only consider this generator a step-next target if not stepping in.
- if (thread_local_.target_frame_count_ < CurrentFrameCount()) return;
- }
-
- DCHECK(!has_suspended_generator());
- thread_local_.suspended_generator_ = *generator_object;
- ClearStepping();
-}
-
class SharedFunctionInfoFinder {
public:
explicit SharedFunctionInfoFinder(int target_position)
@@ -1300,7 +1341,9 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
bool Debug::EnsureBreakInfo(Handle<SharedFunctionInfo> shared) {
// Return if we already have the break info for shared.
if (shared->HasBreakInfo()) return true;
- if (!shared->IsSubjectToDebugging()) return false;
+ if (!shared->IsSubjectToDebugging() && !CanBreakAtEntry(shared)) {
+ return false;
+ }
if (!shared->is_compiled() &&
!Compiler::Compile(shared, Compiler::CLEAR_EXCEPTION)) {
return false;
@@ -1328,7 +1371,10 @@ void Debug::CreateBreakInfo(Handle<SharedFunctionInfo> shared) {
maybe_debug_bytecode_array = factory->CopyBytecodeArray(original);
}
- debug_info->set_flags(debug_info->flags() | DebugInfo::kHasBreakInfo);
+ int flags = debug_info->flags();
+ flags |= DebugInfo::kHasBreakInfo;
+ if (CanBreakAtEntry(shared)) flags |= DebugInfo::kCanBreakAtEntry;
+ debug_info->set_flags(flags);
debug_info->set_debug_bytecode_array(*maybe_debug_bytecode_array);
debug_info->set_break_points(*break_points);
}
@@ -1494,14 +1540,6 @@ MaybeHandle<Object> Debug::MakeExecutionState() {
}
-MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
- // Create the new break event object.
- Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
- break_points_hit };
- return CallFunction("MakeBreakEvent", arraysize(argv), argv);
-}
-
-
MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
bool uncaught,
Handle<Object> promise) {
@@ -1677,29 +1715,15 @@ void Debug::OnDebugBreak(Handle<FixedArray> break_points_hit) {
int inspector_break_points_count = 0;
// This array contains breakpoints installed using JS debug API.
for (int i = 0; i < break_points_hit->length(); ++i) {
- Object* break_point = break_points_hit->get(i);
- if (break_point->IsBreakPoint()) {
- inspector_break_points_hit.push_back(BreakPoint::cast(break_point)->id());
- ++inspector_break_points_count;
- } else {
- break_points_hit->set(i - inspector_break_points_count, break_point);
- }
- }
- int break_points_length =
- break_points_hit->length() - inspector_break_points_count;
- Handle<Object> break_points;
- if (break_points_length) {
- break_points_hit->Shrink(break_points_length);
- break_points = isolate_->factory()->NewJSArrayWithElements(
- break_points_hit, PACKED_ELEMENTS, break_points_length);
- } else {
- break_points = isolate_->factory()->undefined_value();
+ BreakPoint* break_point = BreakPoint::cast(break_points_hit->get(i));
+ inspector_break_points_hit.push_back(break_point->id());
+ ++inspector_break_points_count;
}
debug_delegate_->BreakProgramRequested(
GetDebugEventContext(isolate_),
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
- v8::Utils::ToLocal(break_points), inspector_break_points_hit);
+ inspector_break_points_hit);
}
@@ -1860,6 +1884,16 @@ bool Debug::AllFramesOnStackAreBlackboxed() {
return true;
}
+bool Debug::CanBreakAtEntry(Handle<SharedFunctionInfo> shared) {
+ // Allow break at entry for builtin functions.
+ if (shared->native()) {
+ // Functions that are subject to debugging can have regular breakpoints.
+ DCHECK(!shared->IsSubjectToDebugging());
+ return true;
+ }
+ return false;
+}
+
bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source,
bool preview, bool* stack_changed) {
DebugScope debug_scope(this);
@@ -1971,6 +2005,7 @@ void Debug::UpdateHookOnFunctionCall() {
STATIC_ASSERT(LastStepAction == StepIn);
hook_on_function_call_ = thread_local_.last_step_action_ == StepIn ||
isolate_->needs_side_effect_check();
+ DCHECK_IMPLIES(hook_on_function_call_, is_active_);
}
MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
@@ -2146,7 +2181,6 @@ bool Debug::PerformSideEffectCheck(Handle<JSFunction> function) {
!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
return false;
}
- Deoptimizer::DeoptimizeFunction(*function);
if (!SharedFunctionInfo::HasNoSideEffect(handle(function->shared()))) {
if (FLAG_trace_side_effect_free_debug_evaluate) {
PrintF("[debug-evaluate] Function %s failed side effect check.\n",
@@ -2195,16 +2229,9 @@ void LegacyDebugDelegate::ScriptCompiled(v8::Local<v8::debug::Script> script,
void LegacyDebugDelegate::BreakProgramRequested(
v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state,
- v8::Local<v8::Value> break_points_hit,
const std::vector<debug::BreakpointId>&) {
- Handle<Object> event_data;
- if (isolate_->debug()
- ->MakeBreakEvent(v8::Utils::OpenHandle(*break_points_hit))
- .ToHandle(&event_data)) {
- ProcessDebugEvent(
- v8::Break, Handle<JSObject>::cast(event_data),
- Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
- }
+ ProcessDebugEvent(v8::Break, isolate_->factory()->NewJSObjectWithNullProto(),
+ Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
}
void LegacyDebugDelegate::ExceptionThrown(v8::Local<v8::Context> paused_context,
@@ -2231,32 +2258,6 @@ void LegacyDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
}
}
-JavaScriptDebugDelegate::JavaScriptDebugDelegate(Isolate* isolate,
- Handle<JSFunction> listener,
- Handle<Object> data)
- : LegacyDebugDelegate(isolate) {
- GlobalHandles* global_handles = isolate->global_handles();
- listener_ = global_handles->Create(*listener);
- data_ = global_handles->Create(*data);
-}
-
-JavaScriptDebugDelegate::~JavaScriptDebugDelegate() {
- GlobalHandles::Destroy(Handle<Object>::cast(listener_).location());
- GlobalHandles::Destroy(data_.location());
-}
-
-void JavaScriptDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
- Handle<JSObject> event_data,
- Handle<JSObject> exec_state) {
- AllowJavascriptExecutionDebugOnly allow_script(isolate_);
- Handle<Object> argv[] = {Handle<Object>(Smi::FromInt(event), isolate_),
- exec_state, event_data, data_};
- Handle<JSReceiver> global = isolate_->global_proxy();
- // Listener must not throw.
- Execution::Call(isolate_, listener_, global, arraysize(argv), argv)
- .ToHandleChecked();
-}
-
NativeDebugDelegate::NativeDebugDelegate(Isolate* isolate,
v8::Debug::EventCallback callback,
Handle<Object> data)