[debugger] Consider close-by functions when setting a breakpoint
This changes the behavior of SetBreakpointForScript to find more accurate break positions. Previously, setting a breakpoint would only consider the shared function info that contained the requested position for setting a breakpoint. More intuitively, a breakpoint should not necessarily be set in a function that contains the position, but in the closest breakable location that comes after the position we requested. To achieve this we: 1. find the shared function info of the inner most function that contains the requested_position. This function's end position is used to find other shared function infos in step 2. 2. search for all shared function infos that intersect with the range [requested_position, inner_most_function.break_position[. 3. From the shared function infos extracted in 2, find the one that has the closest breakable location to requested_position. Also-By: bmeurer@chromium.org Fixed: chromium:1137141 Change-Id: I4f4c6c3aac1ebea50cbcad9543b539ab1ded2b05 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2742198 Commit-Queue: Kim-Anh Tran <kimanh@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#73392}
This commit is contained in:
parent
0bb7449983
commit
a7c8a3ea9b
@ -655,13 +655,22 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
|
||||
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
// Obtain shared function info for the function.
|
||||
// Obtain shared function info for the innermost function containing this
|
||||
// position.
|
||||
Handle<Object> result =
|
||||
FindSharedFunctionInfoInScript(script, *source_position);
|
||||
FindInnermostContainingFunctionInfo(script, *source_position);
|
||||
if (result->IsUndefined(isolate_)) return false;
|
||||
|
||||
// Set the breakpoint in the function.
|
||||
auto shared = Handle<SharedFunctionInfo>::cast(result);
|
||||
if (!EnsureBreakInfo(shared)) return false;
|
||||
PrepareFunctionForDebugExecution(shared);
|
||||
|
||||
// Find the nested shared function info that is closest to the position within
|
||||
// the containing function.
|
||||
shared = FindClosestSharedFunctionInfoFromPosition(*source_position, script,
|
||||
shared);
|
||||
|
||||
// Set the breakpoint in the function.
|
||||
return SetBreakpoint(shared, break_point, source_position);
|
||||
}
|
||||
|
||||
@ -1436,7 +1445,7 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
|
||||
std::vector<BreakLocation>* locations) {
|
||||
if (restrict_to_function) {
|
||||
Handle<Object> result =
|
||||
FindSharedFunctionInfoInScript(script, start_position);
|
||||
FindInnermostContainingFunctionInfo(script, start_position);
|
||||
if (result->IsUndefined(isolate_)) return false;
|
||||
|
||||
// Make sure the function has set up the debug info.
|
||||
@ -1450,69 +1459,18 @@ bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool candidateSubsumesRange = false;
|
||||
bool triedTopLevelCompile = false;
|
||||
while (true) {
|
||||
HandleScope scope(isolate_);
|
||||
std::vector<Handle<SharedFunctionInfo>> candidates;
|
||||
std::vector<IsCompiledScope> compiled_scopes;
|
||||
SharedFunctionInfo::ScriptIterator iterator(isolate_, *script);
|
||||
for (SharedFunctionInfo info = iterator.Next(); !info.is_null();
|
||||
info = iterator.Next()) {
|
||||
if (info.EndPosition() < start_position ||
|
||||
info.StartPosition() >= end_position) {
|
||||
continue;
|
||||
}
|
||||
candidateSubsumesRange |= info.StartPosition() <= start_position &&
|
||||
info.EndPosition() >= end_position;
|
||||
if (!info.IsSubjectToDebugging()) continue;
|
||||
if (!info.is_compiled() && !info.allows_lazy_compilation()) continue;
|
||||
candidates.push_back(i::handle(info, isolate_));
|
||||
}
|
||||
|
||||
if (!triedTopLevelCompile && !candidateSubsumesRange &&
|
||||
script->shared_function_infos().length() > 0) {
|
||||
MaybeObject maybeToplevel = script->shared_function_infos().Get(0);
|
||||
HeapObject heap_object;
|
||||
const bool topLevelInfoExists =
|
||||
maybeToplevel->GetHeapObject(&heap_object) &&
|
||||
!heap_object.IsUndefined();
|
||||
if (!topLevelInfoExists) {
|
||||
CompileTopLevel(isolate_, script);
|
||||
triedTopLevelCompile = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool was_compiled = false;
|
||||
for (const auto& candidate : candidates) {
|
||||
IsCompiledScope is_compiled_scope(candidate->is_compiled_scope(isolate_));
|
||||
if (!is_compiled_scope.is_compiled()) {
|
||||
// Code that cannot be compiled lazily are internal and not debuggable.
|
||||
DCHECK(candidate->allows_lazy_compilation());
|
||||
if (!Compiler::Compile(isolate_, candidate, Compiler::CLEAR_EXCEPTION,
|
||||
&is_compiled_scope)) {
|
||||
return false;
|
||||
} else {
|
||||
was_compiled = true;
|
||||
}
|
||||
}
|
||||
DCHECK(is_compiled_scope.is_compiled());
|
||||
compiled_scopes.push_back(is_compiled_scope);
|
||||
if (!EnsureBreakInfo(candidate)) return false;
|
||||
PrepareFunctionForDebugExecution(candidate);
|
||||
}
|
||||
if (was_compiled) continue;
|
||||
|
||||
for (const auto& candidate : candidates) {
|
||||
CHECK(candidate->HasBreakInfo());
|
||||
Handle<DebugInfo> debug_info(candidate->GetDebugInfo(), isolate_);
|
||||
FindBreakablePositions(debug_info, start_position, end_position,
|
||||
locations);
|
||||
}
|
||||
return true;
|
||||
HandleScope scope(isolate_);
|
||||
std::vector<Handle<SharedFunctionInfo>> candidates;
|
||||
if (!FindSharedFunctionInfosIntersectingRange(script, start_position,
|
||||
end_position, &candidates)) {
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE();
|
||||
for (const auto& candidate : candidates) {
|
||||
CHECK(candidate->HasBreakInfo());
|
||||
Handle<DebugInfo> debug_info(candidate->GetDebugInfo(), isolate_);
|
||||
FindBreakablePositions(debug_info, start_position, end_position, locations);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class SharedFunctionInfoFinder {
|
||||
@ -1578,17 +1536,118 @@ SharedFunctionInfo FindSharedFunctionInfoCandidate(int position,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Handle<SharedFunctionInfo> Debug::FindClosestSharedFunctionInfoFromPosition(
|
||||
int position, Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> outer_shared) {
|
||||
CHECK(outer_shared->HasBreakInfo());
|
||||
int closest_position = FindBreakablePosition(
|
||||
Handle<DebugInfo>(outer_shared->GetDebugInfo(), isolate_), position);
|
||||
Handle<SharedFunctionInfo> closest_candidate = outer_shared;
|
||||
if (closest_position == position) return outer_shared;
|
||||
|
||||
const int start_position = outer_shared->StartPosition();
|
||||
const int end_position = outer_shared->EndPosition();
|
||||
if (start_position == end_position) return outer_shared;
|
||||
|
||||
if (closest_position == 0) closest_position = end_position;
|
||||
std::vector<Handle<SharedFunctionInfo>> candidates;
|
||||
// Find all shared function infos of functions that are intersecting from
|
||||
// the requested position until the end of the enclosing function.
|
||||
if (!FindSharedFunctionInfosIntersectingRange(
|
||||
script, position, closest_position, &candidates)) {
|
||||
return outer_shared;
|
||||
}
|
||||
|
||||
for (auto candidate : candidates) {
|
||||
CHECK(candidate->HasBreakInfo());
|
||||
Handle<DebugInfo> debug_info(candidate->GetDebugInfo(), isolate_);
|
||||
const int candidate_position = FindBreakablePosition(debug_info, position);
|
||||
if (candidate_position >= position &&
|
||||
candidate_position < closest_position) {
|
||||
closest_position = candidate_position;
|
||||
closest_candidate = candidate;
|
||||
}
|
||||
if (closest_position == position) break;
|
||||
}
|
||||
return closest_candidate;
|
||||
}
|
||||
|
||||
bool Debug::FindSharedFunctionInfosIntersectingRange(
|
||||
Handle<Script> script, int start_position, int end_position,
|
||||
std::vector<Handle<SharedFunctionInfo>>* intersecting_shared) {
|
||||
bool candidateSubsumesRange = false;
|
||||
bool triedTopLevelCompile = false;
|
||||
|
||||
while (true) {
|
||||
std::vector<Handle<SharedFunctionInfo>> candidates;
|
||||
std::vector<IsCompiledScope> compiled_scopes;
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
SharedFunctionInfo::ScriptIterator iterator(isolate_, *script);
|
||||
for (SharedFunctionInfo info = iterator.Next(); !info.is_null();
|
||||
info = iterator.Next()) {
|
||||
if (info.EndPosition() < start_position ||
|
||||
info.StartPosition() >= end_position) {
|
||||
continue;
|
||||
}
|
||||
candidateSubsumesRange |= info.StartPosition() <= start_position &&
|
||||
info.EndPosition() >= end_position;
|
||||
if (!info.IsSubjectToDebugging()) continue;
|
||||
if (!info.is_compiled() && !info.allows_lazy_compilation()) continue;
|
||||
candidates.push_back(i::handle(info, isolate_));
|
||||
}
|
||||
}
|
||||
|
||||
if (!triedTopLevelCompile && !candidateSubsumesRange &&
|
||||
script->shared_function_infos().length() > 0) {
|
||||
MaybeObject maybeToplevel = script->shared_function_infos().Get(0);
|
||||
HeapObject heap_object;
|
||||
const bool topLevelInfoExists =
|
||||
maybeToplevel->GetHeapObject(&heap_object) &&
|
||||
!heap_object.IsUndefined();
|
||||
if (!topLevelInfoExists) {
|
||||
CompileTopLevel(isolate_, script);
|
||||
triedTopLevelCompile = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool was_compiled = false;
|
||||
for (const auto& candidate : candidates) {
|
||||
IsCompiledScope is_compiled_scope(candidate->is_compiled_scope(isolate_));
|
||||
if (!is_compiled_scope.is_compiled()) {
|
||||
// Code that cannot be compiled lazily are internal and not debuggable.
|
||||
DCHECK(candidate->allows_lazy_compilation());
|
||||
if (!Compiler::Compile(isolate_, candidate, Compiler::CLEAR_EXCEPTION,
|
||||
&is_compiled_scope)) {
|
||||
return false;
|
||||
} else {
|
||||
was_compiled = true;
|
||||
}
|
||||
}
|
||||
DCHECK(is_compiled_scope.is_compiled());
|
||||
compiled_scopes.push_back(is_compiled_scope);
|
||||
if (!EnsureBreakInfo(candidate)) return false;
|
||||
PrepareFunctionForDebugExecution(candidate);
|
||||
}
|
||||
if (was_compiled) continue;
|
||||
*intersecting_shared = std::move(candidates);
|
||||
return true;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// We need to find a SFI for a literal that may not yet have been compiled yet,
|
||||
// and there may not be a JSFunction referencing it. Find the SFI closest to
|
||||
// the given position, compile it to reveal possible inner SFIs and repeat.
|
||||
// While we are at this, also ensure code with debug break slots so that we do
|
||||
// not have to compile a SFI without JSFunction, which is paifu for those that
|
||||
// cannot be compiled without context (need to find outer compilable SFI etc.)
|
||||
Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
|
||||
int position) {
|
||||
Handle<Object> Debug::FindInnermostContainingFunctionInfo(Handle<Script> script,
|
||||
int position) {
|
||||
for (int iteration = 0;; iteration++) {
|
||||
// Go through all shared function infos associated with this script to
|
||||
// find the inner most function containing this position.
|
||||
// find the innermost function containing this position.
|
||||
// If there is no shared function info for this script at all, there is
|
||||
// no point in looking for it by walking the heap.
|
||||
|
||||
@ -1613,7 +1672,6 @@ Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
|
||||
// be no JSFunction referencing it. We can anticipate creating a debug
|
||||
// info while bypassing PrepareFunctionForDebugExecution.
|
||||
if (iteration > 1) {
|
||||
AllowGarbageCollection allow_before_return;
|
||||
CreateBreakInfo(shared_handle);
|
||||
}
|
||||
return shared_handle;
|
||||
|
@ -294,8 +294,16 @@ class V8_EXPORT_PRIVATE Debug {
|
||||
void RemoveAllCoverageInfos();
|
||||
|
||||
// This function is used in FunctionNameUsing* tests.
|
||||
Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script,
|
||||
int position);
|
||||
Handle<Object> FindInnermostContainingFunctionInfo(Handle<Script> script,
|
||||
int position);
|
||||
|
||||
Handle<SharedFunctionInfo> FindClosestSharedFunctionInfoFromPosition(
|
||||
int position, Handle<Script> script,
|
||||
Handle<SharedFunctionInfo> outer_shared);
|
||||
|
||||
bool FindSharedFunctionInfosIntersectingRange(
|
||||
Handle<Script> script, int start_position, int end_position,
|
||||
std::vector<Handle<SharedFunctionInfo>>* candidates);
|
||||
|
||||
static Handle<Object> GetSourceBreakLocations(
|
||||
Isolate* isolate, Handle<SharedFunctionInfo> shared);
|
||||
|
@ -80,7 +80,8 @@ static void CheckFunctionName(v8::Local<v8::Script> script,
|
||||
// Obtain SharedFunctionInfo for the function.
|
||||
Handle<SharedFunctionInfo> shared_func_info =
|
||||
Handle<SharedFunctionInfo>::cast(
|
||||
isolate->debug()->FindSharedFunctionInfoInScript(i_script, func_pos));
|
||||
isolate->debug()->FindInnermostContainingFunctionInfo(i_script,
|
||||
func_pos));
|
||||
|
||||
// Verify inferred function name.
|
||||
std::unique_ptr<char[]> inferred_name =
|
||||
|
@ -64,76 +64,82 @@ assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1);
|
||||
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
[foo()] = 1;
|
||||
[bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
|
||||
// The computed properties are evaluated during class construction,
|
||||
// not as part of the initializer function. As a consequence of which,
|
||||
// they aren't breakable here in the initializer function, but
|
||||
// instead, are part of the enclosing function.
|
||||
//
|
||||
|
||||
function foo() {}
|
||||
var bar = 'bar';
|
||||
|
||||
class X {
|
||||
[foo()] = 1;
|
||||
baz = foo();
|
||||
}
|
||||
|
||||
// class X {
|
||||
// [foo()] = [B0]1;
|
||||
// [bar] = [B1]2;
|
||||
// [baz] = [B2]foo();
|
||||
// [foo()] = 1;
|
||||
// baz = [B0]foo();
|
||||
// }
|
||||
|
||||
initializer = %GetInitializerFunction(X);
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf('[foo()] = 1;') === 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
|
||||
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") === -1);
|
||||
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B0]foo()") > 0);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B0]foo()") === -1);
|
||||
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B1]2;") > 0);
|
||||
b1 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf('baz = [B0]foo()') > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B1]2;") === -1);
|
||||
|
||||
b1 = Debug.setBreakPoint(initializer, 0, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]1;") === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") === -1);
|
||||
|
||||
b2 = Debug.setBreakPoint(initializer, 1, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") > 0);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[bar] = [B0]2;") === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("baz = [B1]foo()") === -1);
|
||||
|
||||
function t() {
|
||||
class X {
|
||||
[foo()] = 1;
|
||||
[bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
}
|
||||
|
||||
b1 = Debug.setBreakPoint(t, 0, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf("[[B0]foo()] = 1;")> 0);
|
||||
// class X {
|
||||
// [[B0]foo()] = 1;
|
||||
// [[B1]bar] = 2;
|
||||
// baz = foo();
|
||||
// }
|
||||
|
||||
b1 = Debug.setBreakPoint(t, 2, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(initializer).indexOf("[[B0]foo()] = 1;") === -1);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') === -1);
|
||||
|
||||
b2 = Debug.setBreakPoint(t, 3, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]bar] = 2;') > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]bar] = [B0]2;') === -1);
|
||||
|
||||
b3 = Debug.setBreakPoint(t, 4, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('baz = foo()') > 0);
|
||||
Debug.clearBreakPoint(b3);
|
||||
|
||||
b1 = Debug.setBreakPoint(t, 2, 0);
|
||||
b2 = Debug.setBreakPoint(t, 3, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') > 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B1]bar] = 2;') > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') === -1);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B1]bar] = 2;') === -1);
|
||||
|
||||
b1 = Debug.setBreakPoint(t, 2, 0);
|
||||
b3 = Debug.setBreakPoint(initializer, 4, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') > 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('baz = foo()') > 0);
|
||||
Debug.clearBreakPoint(b1);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]foo()] = 1;') === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
|
||||
b2 = Debug.setBreakPoint(t, 3, 0);
|
||||
b3 = Debug.setBreakPoint(t, 4, 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]bar] = 2;') > 0);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('baz = foo()') > 0);
|
||||
Debug.clearBreakPoint(b2);
|
||||
assertTrue(Debug.showBreakPoints(t).indexOf('[[B0]bar] = 2;') === -1);
|
||||
Debug.clearBreakPoint(b3);
|
||||
|
@ -34,7 +34,7 @@ function f() {
|
||||
class Derived extends GetBase() {} // 0.
|
||||
}
|
||||
|
||||
var bp = Debug.setBreakPoint(f, 0);
|
||||
var bp = Debug.setBreakPoint(f, 1, 20);
|
||||
f();
|
||||
assertEquals(4, stepCount);
|
||||
|
||||
|
@ -2,7 +2,7 @@ Tests if breakpoint set is first breakable location
|
||||
Set breakpoint outside of any function: (0, 0).
|
||||
Setting breakpoint for id: 3 at 0, 0.
|
||||
No breakable location inside a function was found
|
||||
Set breakpoint adds a breakpoint at (8, 1).
|
||||
Set breakpoint adds a breakpoint at (4, 2).
|
||||
Set breakpoint at a breakable location: (4, 17).
|
||||
Setting breakpoint for id: 3 at 4, 17.
|
||||
Location match for (4, 17).
|
||||
@ -10,4 +10,4 @@ Initial location is expected to be breakable: true.
|
||||
Set breakpoint at non-breakable location: (7, 0).
|
||||
Setting breakpoint for id: 3 at 7, 0.
|
||||
Location match for (7, 2).
|
||||
Initial location is expected to be breakable: false.
|
||||
Initial location is expected to be breakable: false.
|
||||
|
@ -39,10 +39,6 @@ hitBreakpoints contains breakpoint: true
|
||||
|
||||
Set breakpoint at empty line by url in top level function..
|
||||
Breakpoint resolved at:
|
||||
// last line#
|
||||
|
||||
Breakpoint hit at:
|
||||
// last line#
|
||||
|
||||
hitBreakpoints contains breakpoint: true
|
||||
function i2(){#}
|
||||
// last line
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
Checks if we can set a breakpoint on a one-line inline functions.
|
||||
Setting breakpoint on `class X`
|
||||
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
constructor() {
|
||||
|_|this.x = 1;
|
||||
}
|
||||
[bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
new X();
|
||||
|
||||
Setting breakpoint on constructor, should resolve to same location
|
||||
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
constructor() {
|
||||
|_|this.x = 1;
|
||||
}
|
||||
[bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
new X();
|
||||
|
||||
Setting breakpoint on computed properties in class
|
||||
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
constructor() {
|
||||
this.x = 1;
|
||||
}
|
||||
[|_|bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
new X();
|
||||
|
||||
Setting breakpoint on initializer function
|
||||
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
constructor() {
|
||||
this.x = 1;
|
||||
}
|
||||
[bar] = 2;
|
||||
baz = |_|foo();
|
||||
}
|
||||
new X();
|
||||
|
||||
Paused on location:
|
||||
(anonymous) (testInitializer.js:8:3)
|
||||
Paused on location:
|
||||
<instance_members_initializer> (testInitializer.js:9:8)
|
||||
X (testInitializer.js:5:13)
|
||||
(anonymous) (testInitializer.js:11:0)
|
||||
Paused on location:
|
||||
X (testInitializer.js:6:4)
|
||||
(anonymous) (testInitializer.js:11:0)
|
@ -0,0 +1,75 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start(
|
||||
'Checks if we can set a breakpoint on a one-line inline functions.');
|
||||
|
||||
session.setupScriptMap();
|
||||
|
||||
const testClassInitializer = `
|
||||
function foo() {}
|
||||
var bar = "bar";
|
||||
|
||||
class X {
|
||||
constructor() {
|
||||
this.x = 1;
|
||||
}
|
||||
[bar] = 2;
|
||||
baz = foo();
|
||||
}
|
||||
new X();
|
||||
//# sourceURL=testInitializer.js`
|
||||
|
||||
Protocol.Debugger.enable().then(onDebuggerEnabled);
|
||||
|
||||
function onDebuggerEnabled() {
|
||||
Protocol.Runtime.enable();
|
||||
Protocol.Runtime.onExecutionContextCreated(onExecutionContextCreated);
|
||||
}
|
||||
|
||||
async function onExecutionContextCreated(messageObject) {
|
||||
const executionContextId = messageObject.params.context.id;
|
||||
await runTest(executionContextId, testClassInitializer, 'testInitializer.js');
|
||||
InspectorTest.completeTest();
|
||||
}
|
||||
|
||||
async function runTest(executionContextId, func, url) {
|
||||
const obj = await Protocol.Runtime.compileScript({
|
||||
expression: func,
|
||||
sourceURL: url,
|
||||
persistScript: true,
|
||||
executionContextId: executionContextId
|
||||
});
|
||||
const scriptId = obj.result.scriptId;
|
||||
|
||||
InspectorTest.log('Setting breakpoint on `class X`');
|
||||
await setBreakpoint(4, 'testInitializer.js');
|
||||
|
||||
InspectorTest.log(
|
||||
'Setting breakpoint on constructor, should resolve to same location');
|
||||
await setBreakpoint(5, 'testInitializer.js');
|
||||
|
||||
InspectorTest.log('Setting breakpoint on computed properties in class');
|
||||
await setBreakpoint(8, 'testInitializer.js');
|
||||
|
||||
InspectorTest.log('Setting breakpoint on initializer function');
|
||||
await setBreakpoint(9, 'testInitializer.js');
|
||||
|
||||
Protocol.Runtime.runScript({scriptId});
|
||||
const numBreaks = 3;
|
||||
for (var i = 0; i < numBreaks; ++i) {
|
||||
const {params: {callFrames}} = await Protocol.Debugger.oncePaused();
|
||||
InspectorTest.log('Paused on location:');
|
||||
session.logCallFrames(callFrames);
|
||||
Protocol.Debugger.resume();
|
||||
}
|
||||
|
||||
InspectorTest.completeTest();
|
||||
};
|
||||
|
||||
async function setBreakpoint(lineNumber, url) {
|
||||
const {result: {locations}} =
|
||||
await Protocol.Debugger.setBreakpointByUrl({lineNumber, url});
|
||||
await session.logBreakLocations(locations);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
Checks if we can set a breakpoint on a one-line inline functions.
|
||||
Setting breakpoint
|
||||
function test() {
|
||||
function func(a) {|_|console.log(a);}
|
||||
func("hi");
|
||||
}
|
||||
|
||||
Paused on location:
|
||||
func (testFunction.js:1:22)
|
||||
test (testFunction.js:2:4)
|
||||
(anonymous) (:0:0)
|
31
test/inspector/debugger/set-breakpoint-inline-function.js
Normal file
31
test/inspector/debugger/set-breakpoint-inline-function.js
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2021 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
let {session, contextGroup, Protocol} = InspectorTest.start(
|
||||
'Checks if we can set a breakpoint on a one-line inline functions.');
|
||||
|
||||
session.setupScriptMap();
|
||||
const testFunction = ` function test() {
|
||||
function func(a) {console.log(a);}
|
||||
func("hi");
|
||||
}
|
||||
//# sourceURL=testFunction.js`;
|
||||
|
||||
contextGroup.addScript(testFunction);
|
||||
|
||||
(async function testSetBreakpoint() {
|
||||
await Protocol.Debugger.enable();
|
||||
await Protocol.Runtime.enable();
|
||||
|
||||
InspectorTest.log('Setting breakpoint');
|
||||
const {result: {locations}} = await Protocol.Debugger.setBreakpointByUrl(
|
||||
{lineNumber: 1, url: 'testFunction.js'});
|
||||
await session.logBreakLocations(locations);
|
||||
|
||||
Protocol.Runtime.evaluate({expression: 'test()'});
|
||||
const {params: {callFrames}} = await Protocol.Debugger.oncePaused();
|
||||
InspectorTest.log('Paused on location:');
|
||||
session.logCallFrames(callFrames);
|
||||
InspectorTest.completeTest();
|
||||
})();
|
@ -92,22 +92,10 @@ eval('function sourceUrlFunc() { a = 2; }\\n//# sourceURL=sourceUrlScript');`);
|
||||
Protocol.Runtime.evaluate({
|
||||
expression: `//# sourceURL=test-script\nfunction i1(){};\n\n\n\n\nfunction i2(){}\n// last line`
|
||||
});
|
||||
const [{
|
||||
params:{location}
|
||||
}, {
|
||||
params:{
|
||||
callFrames:[topFrame],
|
||||
hitBreakpoints
|
||||
}
|
||||
}] = await Promise.all([
|
||||
Protocol.Debugger.onceBreakpointResolved(),
|
||||
Protocol.Debugger.oncePaused()]);
|
||||
const [{params: {location}}] =
|
||||
await Promise.all([Protocol.Debugger.onceBreakpointResolved()]);
|
||||
InspectorTest.log('Breakpoint resolved at:');
|
||||
await session.logSourceLocation(location);
|
||||
InspectorTest.log('Breakpoint hit at:');
|
||||
await session.logSourceLocation(topFrame.location);
|
||||
const hitBreakpoint = hitBreakpoints[0] === breakpointId;
|
||||
InspectorTest.log(`hitBreakpoints contains breakpoint: ${hitBreakpoint}\n`);
|
||||
}
|
||||
await Protocol.Debugger.disable();
|
||||
InspectorTest.completeTest();
|
||||
|
Loading…
Reference in New Issue
Block a user