Index: src/debug/debug.cc |
diff --git a/src/debug/debug.cc b/src/debug/debug.cc |
index f257f67e29c2975e0529257a1e424091af0e633d..63687c00a6ec77363f27c4e8fab23936396fa823 100644 |
--- a/src/debug/debug.cc |
+++ b/src/debug/debug.cc |
@@ -511,7 +511,7 @@ void Debug::Break(JavaScriptFrame* frame) { |
// Return if we fail to retrieve debug info. |
Handle<JSFunction> function(frame->function()); |
Handle<SharedFunctionInfo> shared(function->shared()); |
- if (!EnsureDebugInfo(shared)) return; |
+ if (!EnsureBreakInfo(shared)) return; |
Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); |
// Find the break location where execution has stopped. |
@@ -612,7 +612,7 @@ bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { |
FrameSummary summary = FrameSummary::GetTop(frame); |
DCHECK(!summary.IsWasm()); |
Handle<JSFunction> function = summary.AsJavaScript().function(); |
- if (!function->shared()->HasDebugInfo()) return false; |
+ if (!function->shared()->HasBreakInfo()) return false; |
Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
// Enter the debugger. |
DebugScope debug_scope(this); |
@@ -678,7 +678,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function, |
// Make sure the function is compiled and has set up the debug info. |
Handle<SharedFunctionInfo> shared(function->shared()); |
- if (!EnsureDebugInfo(shared)) return true; |
+ if (!EnsureBreakInfo(shared)) return true; |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
// Source positions starts with zero. |
DCHECK(*source_position >= 0); |
@@ -718,7 +718,7 @@ bool Debug::SetBreakPointForScript(Handle<Script> script, |
// Make sure the function has set up the debug info. |
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); |
- if (!EnsureDebugInfo(shared)) return false; |
+ if (!EnsureBreakInfo(shared)) return false; |
// Find position within function. The script position might be before the |
// source position of the first function. |
@@ -809,7 +809,7 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) { |
ClearBreakPoints(debug_info); |
if (debug_info->GetBreakPointCount() == 0) { |
- RemoveDebugInfoAndClearFromShared(debug_info); |
+ RemoveBreakInfoAndMaybeFree(debug_info); |
} else { |
ApplyBreakPoints(debug_info); |
} |
@@ -818,17 +818,21 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
} |
} |
-// Clear out all the debug break code. This is ONLY supposed to be used when |
-// shutting down the debugger as it will leave the break point information in |
-// DebugInfo even though the code is patched back to the non break point state. |
+// Clear out all the debug break code. |
void Debug::ClearAllBreakPoints() { |
- for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
- node = node->next()) { |
- ClearBreakPoints(node->debug_info()); |
- } |
- // Remove all debug info. |
- while (debug_info_list_ != NULL) { |
- RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
+ DebugInfoListNode* prev = nullptr; |
+ DebugInfoListNode* current = debug_info_list_; |
+ while (current != nullptr) { |
+ DebugInfoListNode* next = current->next(); |
+ Handle<DebugInfo> debug_info = current->debug_info(); |
+ ClearBreakPoints(debug_info); |
+ if (debug_info->ClearBreakInfo()) { |
+ FreeDebugInfoListNode(prev, current); |
+ current = next; |
+ } else { |
+ prev = current; |
+ current = next; |
+ } |
} |
} |
@@ -836,7 +840,7 @@ void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared, |
bool returns_only) { |
if (IsBlackboxed(shared)) return; |
// Make sure the function is compiled and has set up the debug info. |
- if (!EnsureDebugInfo(shared)) return; |
+ if (!EnsureBreakInfo(shared)) return; |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
// Flood the function with break points. |
if (debug_info->HasDebugCode()) { |
@@ -1031,7 +1035,7 @@ void Debug::PrepareStep(StepAction step_action) { |
auto summary = FrameSummary::GetTop(frame).AsJavaScript(); |
Handle<JSFunction> function(summary.function()); |
Handle<SharedFunctionInfo> shared(function->shared()); |
- if (!EnsureDebugInfo(shared)) return; |
+ if (!EnsureBreakInfo(shared)) return; |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); |
@@ -1121,7 +1125,7 @@ Handle<Object> Debug::GetSourceBreakLocations( |
Handle<SharedFunctionInfo> shared, |
BreakPositionAlignment position_alignment) { |
Isolate* isolate = shared->GetIsolate(); |
- if (!shared->HasDebugInfo()) { |
+ if (!shared->HasBreakInfo()) { |
return isolate->factory()->undefined_value(); |
} |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
@@ -1399,7 +1403,7 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, |
// Make sure the function has set up the debug info. |
Handle<SharedFunctionInfo> shared = |
Handle<SharedFunctionInfo>::cast(result); |
- if (!EnsureDebugInfo(shared)) return false; |
+ if (!EnsureBreakInfo(shared)) return false; |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
FindBreakablePositions(debug_info, start_position, end_position, locations); |
@@ -1432,12 +1436,12 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, |
was_compiled = true; |
} |
} |
- if (!EnsureDebugInfo(candidates[i])) return false; |
+ if (!EnsureBreakInfo(candidates[i])) return false; |
} |
if (was_compiled) continue; |
for (int i = 0; i < candidates.length(); ++i) { |
- CHECK(candidates[i]->HasDebugInfo()); |
+ CHECK(candidates[i]->HasBreakInfo()); |
Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); |
FindBreakablePositions(debug_info, start_position, end_position, |
locations); |
@@ -1544,7 +1548,7 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
// info while bypassing PrepareFunctionForBreakpoints. |
if (iteration > 1) { |
AllowHeapAllocation allow_before_return; |
- CreateDebugInfo(shared_handle); |
+ CreateBreakInfo(shared_handle); |
} |
return shared_handle; |
} |
@@ -1560,9 +1564,9 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, |
// Ensures the debug information is present for shared. |
-bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
- // Return if we already have the debug info for shared. |
- if (shared->HasDebugInfo()) return true; |
+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->is_compiled() && !Compiler::CompileDebugCode(shared)) { |
return false; |
@@ -1571,51 +1575,91 @@ bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
// 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); |
+ CreateBreakInfo(shared); |
CHECK(PrepareFunctionForBreakPoints(shared)); |
return true; |
} |
+void Debug::CreateBreakInfo(Handle<SharedFunctionInfo> shared) { |
+ HandleScope scope(isolate_); |
+ Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); |
-void Debug::CreateDebugInfo(Handle<SharedFunctionInfo> shared) { |
- // Create the debug info object. |
- Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); |
+ // Initialize with break information. |
- // Add debug info to the list. |
+ DCHECK(!debug_info->HasBreakInfo()); |
+ |
+ Factory* factory = isolate_->factory(); |
+ Handle<FixedArray> break_points( |
+ factory->NewFixedArray(DebugInfo::kEstimatedNofBreakPointsInFunction)); |
+ |
+ // Make a copy of the bytecode array if available. |
+ Handle<Object> maybe_debug_bytecode_array = factory->undefined_value(); |
+ if (shared->HasBytecodeArray()) { |
+ Handle<BytecodeArray> original(shared->bytecode_array()); |
+ maybe_debug_bytecode_array = factory->CopyBytecodeArray(original); |
+ } |
+ |
+ debug_info->set_flags(debug_info->flags() | DebugInfo::kHasBreakInfo); |
+ debug_info->set_debug_bytecode_array(*maybe_debug_bytecode_array); |
+ debug_info->set_break_points(*break_points); |
+} |
+ |
+Handle<DebugInfo> Debug::GetOrCreateDebugInfo( |
+ Handle<SharedFunctionInfo> shared) { |
+ if (shared->HasDebugInfo()) return handle(shared->GetDebugInfo()); |
+ |
+ // Create debug info and add it to the list. |
+ Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); |
DebugInfoListNode* node = new DebugInfoListNode(*debug_info); |
node->set_next(debug_info_list_); |
debug_info_list_ = node; |
-} |
+ return debug_info; |
+} |
-void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) { |
+void Debug::FindDebugInfo(Handle<DebugInfo> debug_info, |
+ DebugInfoListNode** prev, DebugInfoListNode** curr) { |
HandleScope scope(isolate_); |
- Handle<SharedFunctionInfo> shared(debug_info->shared()); |
- |
- DCHECK_NOT_NULL(debug_info_list_); |
- // Run through the debug info objects to find this one and remove it. |
- DebugInfoListNode* prev = NULL; |
- DebugInfoListNode* current = debug_info_list_; |
- while (current != NULL) { |
- if (current->debug_info().is_identical_to(debug_info)) { |
- // Unlink from list. If prev is NULL we are looking at the first element. |
- if (prev == NULL) { |
- debug_info_list_ = current->next(); |
- } else { |
- prev->set_next(current->next()); |
- } |
- shared->set_debug_info(Smi::FromInt(debug_info->debugger_hints())); |
- delete current; |
- return; |
- } |
- // Move to next in list. |
- prev = current; |
- current = current->next(); |
+ *prev = nullptr; |
+ *curr = debug_info_list_; |
+ while (*curr != nullptr) { |
+ if ((*curr)->debug_info().is_identical_to(debug_info)) return; |
+ *prev = *curr; |
+ *curr = (*curr)->next(); |
} |
UNREACHABLE(); |
} |
+void Debug::RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info) { |
+ bool should_unlink = debug_info->ClearBreakInfo(); |
+ if (should_unlink) { |
+ DebugInfoListNode* prev; |
+ DebugInfoListNode* node; |
+ FindDebugInfo(debug_info, &prev, &node); |
+ FreeDebugInfoListNode(prev, node); |
+ } |
+} |
+ |
+void Debug::FreeDebugInfoListNode(DebugInfoListNode* prev, |
+ DebugInfoListNode* node) { |
+ DCHECK(node->debug_info()->IsEmpty()); |
+ |
+ // Unlink from list. If prev is NULL we are looking at the first element. |
+ if (prev == nullptr) { |
+ debug_info_list_ = node->next(); |
+ } else { |
+ prev->set_next(node->next()); |
+ } |
+ |
+ // Pack debugger hints back into the SFI::debug_info field. |
+ Handle<DebugInfo> debug_info(node->debug_info()); |
+ debug_info->shared()->set_debug_info( |
+ Smi::FromInt(debug_info->debugger_hints())); |
+ |
+ delete node; |
+} |
+ |
bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
HandleScope scope(isolate_); |
@@ -1623,7 +1667,7 @@ bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
Handle<SharedFunctionInfo> shared(frame->function()->shared()); |
// With no debug info there are no break points, so we can't be at a return. |
- if (!shared->HasDebugInfo()) return false; |
+ if (!shared->HasBreakInfo()) return false; |
DCHECK(!frame->is_optimized()); |
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |