debugger statement is ignored in iframes removed from the document

This patch is conditioning the message `ContextWillBeDestroyed` to `MainThreadDebugger` during context disposal to happen only if the reason we are disposing the context is not `ClearForClose`.
The reason for such change is that the context of a detached iframe can still be used to execute code via iframe's `eval` and it would be useful to debug such code.
`ContextWillBeDestroyed` sends V8Inspector a `contextDestroyed` message where the inspector disposes data structures related with that context. Such message is also sent to V8Inspector when a context gets collected
by V8 GC, meaning that we were prematurely disposing such data
structures during frame dettachment and disallowing debuggability for
code using those contexts.
Since InspectedContexts holds a weak reference to a context and there's no strong reference from V8Inspector, this change doesn't leak memory by
holding contexts alive. Since there are multiple tests that rely on
`Runtime.executionContextDestroyed` message, we updated them to perform a GC after frame detachment, so the test could still work as expected.

Bug: 1015462
Change-Id: I6014bd8ddbfb1d3838b5364ccc9520b3b363b5fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2965275
Reviewed-by: Nate Chapin <japhet@chromium.org>
Reviewed-by: Mathias Bynens <mathias@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
Commit-Queue: José Dapena Paz <jdapena@igalia.com>
Cr-Commit-Position: refs/heads/master@{#908362}
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index f14ee64..e8a2cef 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -823,6 +823,7 @@
     self._driver.SwitchToFrame('id')
     self.assertTrue(self._driver.ExecuteScript('return window.top != window'))
     self._driver.ExecuteScript('parent.postMessage("remove", "*");')
+    self._driver.SwitchToMainFrame()
     self.assertTrue(self._driver.ExecuteScript('return window.top == window'))
 
   def testSwitchToStaleFrame(self):
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
index 82750b5..fbef520 100644
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -100,7 +100,20 @@
   // willReleaseScriptContext callback, so all disposing should happen after
   // it returns.
   GetFrame()->Client()->WillReleaseScriptContext(context, world_->GetWorldId());
-  MainThreadDebugger::Instance()->ContextWillBeDestroyed(script_state_);
+
+  // We don't notify context destruction during frame detachment that happens
+  // when we remove the frame from the DOM tree. This allows debug code evaled
+  // from those frames. However, we still want to notify that the context was
+  // destroyed when navigating between documents, because DevTools is designed
+  // to only show what's going on "currently".
+  // Also, delaying such message won't leak memory because
+  // `V8InspectorImpl::contextCollected` is also called when the context for
+  // detached iframe is collected by GC.
+  if (next_status != Lifecycle::kFrameIsDetached &&
+      next_status != Lifecycle::kFrameIsDetachedAndV8MemoryIsPurged) {
+    MainThreadDebugger::Instance()->ContextWillBeDestroyed(script_state_);
+  }
+
   if (next_status == Lifecycle::kV8MemoryIsForciblyPurged ||
       next_status == Lifecycle::kGlobalObjectIsDetached) {
     // Clean up state on the global proxy, which will be reused.
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach-expected.txt
index 0d378e8..5d8e6fa 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach-expected.txt
@@ -20,15 +20,15 @@
 [+] _test_attachFrame.js
 
 Running: detachFrame
-Removed: 3 uiSourceCodes
+Removed: 2 uiSourceCodes
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-frame.html
-[-] http://127.0.0.1:8000/devtools/bindings/resources/magic-script.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-style.css
-Workspace: 7 uiSourceCodes.
+Workspace: 8 uiSourceCodes.
     debugger:///VM[XXX]
     debugger:///VM[XXX] magic-script.js
     debugger:///VM[XXX] _test_attachFrame.js
 [+] debugger:///VM[XXX] _test_detachFrame.js
+    http://127.0.0.1:8000/devtools/bindings/resources/magic-script.js
     http://127.0.0.1:8000/devtools/resources/inspected-page.html
     _test_attachFrame.js
 [+] _test_detachFrame.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach.js b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach.js
index fb3c37b..00927f87 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-frame-attach-detach.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that UISourceCodes are added and removed as iframe gets attached and detached.\n`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
@@ -16,6 +16,5 @@
   TestRunner.markStep('detachFrame');
   await BindingsTestRunner.detachFrame('frame', '_test_detachFrame.js');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
-
   TestRunner.completeTest();
 })();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames-expected.txt
index 046f233..f95b30da 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames-expected.txt
@@ -26,7 +26,8 @@
 Running: detachFrame1
 Removed: 1 uiSourceCodes
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-script.js
-Workspace: 13 uiSourceCodes.
+Workspace: 14 uiSourceCodes.
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX]
     debugger:///VM[XXX] magic-script.js
     debugger:///VM[XXX] magic-script.js
@@ -46,8 +47,10 @@
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-frame.html
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-script.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/magic-style.css
-Workspace: 12 uiSourceCodes.
+Workspace: 14 uiSourceCodes.
     debugger:///VM[XXX]
+    debugger:///VM[XXX]
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX] magic-script.js
     debugger:///VM[XXX] magic-script.js
     debugger:///VM[XXX] _test_create-iframe1.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames.js
index 1b0f949..c1a90f3 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/bindings-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that UISourceCodes are removed as iframes are getting detached.\n`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
@@ -18,10 +18,12 @@
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames-expected.txt
index a2a5f59..9c67790 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames-expected.txt
@@ -39,8 +39,9 @@
 Running: detachFrame1
 Removed: 1 uiSourceCodes
 [-] content-script-42.js
-Workspace: 14 uiSourceCodes.
+Workspace: 15 uiSourceCodes.
     content-script-42.js
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX]
     debugger:///VM[XXX] content-script-42.js
     debugger:///VM[XXX] content-script-42.js
@@ -59,7 +60,9 @@
 Removed: 2 uiSourceCodes
 [-] content-script-42.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/contentscript-frame.html
-Workspace: 14 uiSourceCodes.
+Workspace: 16 uiSourceCodes.
+[+] debugger:///VM[XXX]
+    debugger:///VM[XXX]
     debugger:///VM[XXX]
     debugger:///VM[XXX] content-script-42.js
     debugger:///VM[XXX] content-script-42.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames.js
index 01f404b..acccb0d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-bindings-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that SourceMap bindings are generating UISourceCodes properly.\n`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
@@ -19,10 +19,12 @@
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.js
index d54231d..e509cf6d 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/contentscripts-navigator-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that SourceMap bindings are generating UISourceCodes properly.\n`);
   await TestRunner.loadModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadTestModule('bindings_test_runner');
@@ -15,18 +15,20 @@
 
   TestRunner.markStep('attachFrame1');
   await BindingsTestRunner.attachFrame('frame1', './resources/contentscript-frame.html', '_test_attachFrame1.js'),
-      SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
+    SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
 
   TestRunner.markStep('attachFrame2');
   await BindingsTestRunner.attachFrame('frame2', './resources/contentscript-frame.html', '_test_attachFrame2.js'),
-      SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
+    SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(contentScriptsNavigator, false);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach-expected.txt
index 3161791..3a7d69c8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach-expected.txt
@@ -21,16 +21,16 @@
 [+] _test_attachFrame.js
 
 Running: detachFrame
-Removed: 3 uiSourceCodes
-[-] dynamic-script.js
+Removed: 2 uiSourceCodes
 [-] dynamic-style.css
 [-] http://127.0.0.1:8000/devtools/bindings/resources/dynamic-frame.html
-Workspace: 8 uiSourceCodes.
+Workspace: 9 uiSourceCodes.
     debugger:///VM[XXX]
     debugger:///VM[XXX] dynamic-frame.html
     debugger:///VM[XXX] dynamic-script.js
     debugger:///VM[XXX] _test_attachFrame.js
 [+] debugger:///VM[XXX] _test_detachFrame.js
+    dynamic-script.js
     http://127.0.0.1:8000/devtools/resources/inspected-page.html
     _test_attachFrame.js
 [+] _test_detachFrame.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach.js b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach.js
index dc9ea6c..d7169b78 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-bindings-frame-attach-detach.js
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(
-      `Verify that UISourceCodes are added and removed as iframe with dynamic script and stylesheet is added and removed.\n`);
+    `Verify that UISourceCodes are added and removed as iframe with dynamic script and stylesheet is added and removed.\n`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
   TestRunner.markStep('dumpInitialWorkspace');
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
index fcfe525..bd962ed 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/dynamic-navigator-frame-attach-detach-expected.txt
@@ -25,4 +25,7 @@
   127.0.0.1:8000
     devtools/resources
       inspected-page.html
+  frame (dynamic-frame.html)
+    (no domain)
+      dynamic-script.js
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources-expected.txt
index 432e72a..17b7f5f 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources-expected.txt
@@ -62,7 +62,8 @@
 Running: detachAnotherFrame1
 Removed: 1 uiSourceCodes
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/script1.js
-Workspace: 20 uiSourceCodes.
+Workspace: 21 uiSourceCodes.
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX]
     debugger:///VM[XXX] script1.js
     debugger:///VM[XXX] script1.js
@@ -89,8 +90,10 @@
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/frame2.html
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/script2.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/unique2.ts
-Workspace: 19 uiSourceCodes.
+Workspace: 21 uiSourceCodes.
     debugger:///VM[XXX]
+    debugger:///VM[XXX]
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX] script1.js
     debugger:///VM[XXX] script1.js
     debugger:///VM[XXX] script2.js
@@ -116,8 +119,11 @@
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/frame1.html
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/script1.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/jssourcemaps-with-overlapping-sources/unique1.ts
-Workspace: 17 uiSourceCodes.
+Workspace: 20 uiSourceCodes.
     debugger:///VM[XXX]
+    debugger:///VM[XXX]
+    debugger:///VM[XXX]
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX] script1.js
     debugger:///VM[XXX] script1.js
     debugger:///VM[XXX] script2.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources.js b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources.js
index d24820b..47e9f8c 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-bindings-overlapping-sources.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that JavaScript SourceMap handle different sourcemap with overlapping sources.`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
@@ -32,14 +32,17 @@
 
   TestRunner.markStep('detachAnotherFrame1');
   await BindingsTestRunner.detachFrame('anotherFrame1', '_test_detach-anotherFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-navigator-overlapping-sources.js b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-navigator-overlapping-sources.js
index 8651147..c681bcb 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-navigator-overlapping-sources.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/jssourcemap-navigator-overlapping-sources.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that JavaScript SourceMap handle different sourcemaps with overlapping sources.`);
   await TestRunner.loadModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadTestModule('bindings_test_runner');
@@ -36,14 +36,17 @@
 
   TestRunner.markStep('detachAnotherFrame1');
   await BindingsTestRunner.detachFrame('anotherFrame1', '_test_detach-anotherFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/livelocation-main-frame-navigated-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/livelocation-main-frame-navigated-expected.txt
index 2c18911..2e74349 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/livelocation-main-frame-navigated-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/livelocation-main-frame-navigated-expected.txt
@@ -9,8 +9,8 @@
 [ UPDATE ]  LiveLocation-css: null
 [ UPDATE ]  LiveLocation-css: null
 [ UPDATE ]  LiveLocation-js: http://127.0.0.1:8000/devtools/bindings/resources/sourcemap-script.js:0:0
-[ UPDATE ]  LiveLocation-js: debugger:///VM[XXX] sourcemap-script.js:0:0
-[ UPDATE ]  LiveLocation-js: debugger:///VM[XXX] sourcemap-script.js:0:0
+[ UPDATE ]  LiveLocation-js: null
+[ UPDATE ]  LiveLocation-js: null
 [  GET   ]  LiveLocation-js: null
 [  GET   ]  LiveLocation-css: null
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
index 6c00310..2ddde891 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach-expected.txt
@@ -24,4 +24,8 @@
   127.0.0.1:8000
     devtools/resources
       inspected-page.html
+  frame (magic-frame.html)
+    127.0.0.1:8000
+      devtools/bindings/resources
+        magic-script.js
 
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach.js b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach.js
index 1950536f..05eaacf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-frame-attach-detach.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that navigator is rendered properly when frames come and go.\n`);
   await TestRunner.loadModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadTestModule('bindings_test_runner');
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-multiple-frames.js
index 348530f5..0638f9e 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/navigator-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that navigator is properly rendered in case of multiple iframes.\n`);
   await TestRunner.loadModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadTestModule('bindings_test_runner');
@@ -22,10 +22,12 @@
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames-expected.txt b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames-expected.txt
index 003444a..f9fef08 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames-expected.txt
@@ -28,7 +28,8 @@
 Running: detachFrame1
 Removed: 1 uiSourceCodes
 [-] http://127.0.0.1:8000/devtools/bindings/resources/sourcemap-script.js
-Workspace: 15 uiSourceCodes.
+Workspace: 16 uiSourceCodes.
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX]
     debugger:///VM[XXX] sourcemap-script.js
     debugger:///VM[XXX] sourcemap-script.js
@@ -52,8 +53,10 @@
 [-] http://127.0.0.1:8000/devtools/bindings/resources/sourcemap-script.js
 [-] http://127.0.0.1:8000/devtools/bindings/resources/sourcemap-style.css
 [-] http://127.0.0.1:8000/devtools/bindings/resources/sourcemap-typescript.ts
-Workspace: 12 uiSourceCodes.
+Workspace: 14 uiSourceCodes.
     debugger:///VM[XXX]
+    debugger:///VM[XXX]
+[+] debugger:///VM[XXX]
     debugger:///VM[XXX] sourcemap-script.js
     debugger:///VM[XXX] sourcemap-script.js
     debugger:///VM[XXX] _test_create-iframe1.js
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
index 7d843357..f29ec71b 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-bindings-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that SourceMap bindings are generating UISourceCodes properly.\n`);
   await TestRunner.loadTestModule('bindings_test_runner');
 
@@ -20,10 +20,12 @@
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   snapshot = BindingsTestRunner.dumpWorkspace(snapshot);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.js b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.js
index c1935f0..c9cadcf 100644
--- a/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.js
+++ b/third_party/blink/web_tests/http/tests/devtools/bindings/sourcemap-navigator-multiple-frames.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-(async function() {
+(async function () {
   TestRunner.addResult(`Verify that SourceMap sources are correctly displayed in navigator.\n`);
   await TestRunner.loadModule('sources'); await TestRunner.loadTestModule('sources_test_runner');
   await TestRunner.loadTestModule('bindings_test_runner');
@@ -31,10 +31,12 @@
 
   TestRunner.markStep('detachFrame1');
   await BindingsTestRunner.detachFrame('frame1', '_test_detachFrame1.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.markStep('detachFrame2');
   await BindingsTestRunner.detachFrame('frame2', '_test_detachFrame2.js');
+  await TestRunner.evaluateInPageAnonymously('GCController.collectAll()');
   SourcesTestRunner.dumpNavigatorView(sourcesNavigator, false);
 
   TestRunner.completeTest();
diff --git a/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe-expected.txt b/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe-expected.txt
new file mode 100644
index 0000000..5a76cff
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe-expected.txt
@@ -0,0 +1,10 @@
+Tests that debugger statement stops execution from eval on detached iframes
+
+
+Running: 
+Script execution paused.
+Call stack:
+    0)  (:1)
+    1)  (stop-on-debugger-from-detached-iframe.js:25)
+Script execution resumed.
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe.js b/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe.js
new file mode 100644
index 0000000..3cfddf8
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/debugger/stop-on-debugger-from-detached-iframe.js
@@ -0,0 +1,28 @@
+// Copyright 2021 Igalia S.A. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function () {
+  TestRunner.addResult('Tests that debugger statement stops execution from eval on detached iframes\n');
+  await TestRunner.loadTestModule('sources_test_runner');
+  await TestRunner.showPanel('sources');
+
+  let script = `
+    i = document.createElement('iframe');
+    document.body.appendChild(i);
+    w = i.contentWindow;
+    w.eval('window');
+    i.remove();
+    w.eval('debugger;window');
+  `;
+
+  SourcesTestRunner.runDebuggerTestSuite([function (next) {
+    SourcesTestRunner.waitUntilPaused(paused);
+    TestRunner.evaluateInPage(script);
+
+    async function paused(callFrames) {
+      await SourcesTestRunner.captureStackTrace(callFrames);
+      SourcesTestRunner.resumeExecution(next);
+    }
+  }]);
+})();
diff --git a/third_party/blink/web_tests/inspector-protocol/page/frameNavigatedContext.js b/third_party/blink/web_tests/inspector-protocol/page/frameNavigatedContext.js
index bc0e23b..2e83e95 100644
--- a/third_party/blink/web_tests/inspector-protocol/page/frameNavigatedContext.js
+++ b/third_party/blink/web_tests/inspector-protocol/page/frameNavigatedContext.js
@@ -1,5 +1,5 @@
-(async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(`Tests context lifetime events relative to frame's ones.`);
+(async function (testRunner) {
+  var { page, session, dp } = await testRunner.startBlank(`Tests context lifetime events relative to frame's ones.`);
 
   await dp.Runtime.enable();
   await dp.Page.enable();
@@ -25,6 +25,7 @@
     window.frame = document.createElement('iframe');
     frame.src = '${testRunner.url('../resources/blank.html')}';
     document.body.appendChild(frame);
+
   `);
 
   await dp.Runtime.onceExecutionContextCreated();
@@ -37,7 +38,10 @@
   await dp.Runtime.onceExecutionContextCreated();
 
   testRunner.log('\nUnloading iframe');
-  session.evaluate(`frame.remove();`);
+  session.evaluate(`
+    frame.remove();
+    GCController.collectAll();
+  `);
 
   await dp.Runtime.onceExecutionContextDestroyed();
 
diff --git a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-execution-contexts-events.js b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-execution-contexts-events.js
index c78e91eb..c01fb769 100644
--- a/third_party/blink/web_tests/inspector-protocol/runtime/runtime-execution-contexts-events.js
+++ b/third_party/blink/web_tests/inspector-protocol/runtime/runtime-execution-contexts-events.js
@@ -1,5 +1,5 @@
-(async function(testRunner) {
-  var {page, session, dp} = await testRunner.startBlank(`Tests execution context lifetime events.`);
+(async function (testRunner) {
+  var { page, session, dp } = await testRunner.startBlank(`Tests execution context lifetime events.`);
 
   dp.Runtime.enable();
   await dp.Runtime.onceExecutionContextCreated();
@@ -18,7 +18,10 @@
 
   await loadPromise;
   testRunner.log('Navigate frame');
-  session.evaluate(`window.frames[0].location = '${testRunner.url('../resources/runtime-events-iframe.html')}'`);
+  session.evaluate(`
+    window.frames[0].location = '${testRunner.url('../resources/runtime-events-iframe.html')}'
+    GCController.collectAll();
+  `);
   var executionContextId = (await dp.Runtime.onceExecutionContextDestroyed()).params.executionContextId;
   if (frameExecutionContextId !== executionContextId) {
     testRunner.fail(`Execution context with id = ${executionContextId} was destroyed, but iframe's executionContext had id = ${frameExecutionContextId} before navigation`);
@@ -31,7 +34,10 @@
   testRunner.log('Frame context was created');
 
   testRunner.log('Remove frame');
-  session.evaluate(`document.querySelector('#iframe').remove()`);
+  session.evaluate(`
+    document.querySelector('#iframe').remove();
+    GCController.collectAll();
+  `);
   executionContextId = (await dp.Runtime.onceExecutionContextDestroyed()).params.executionContextId;
   if (frameExecutionContextId !== executionContextId) {
     testRunner.fail(`Deleted frame had execution context with id = ${frameExecutionContextId}, but executionContext with id = ${executionContextId} was removed`);
@@ -53,7 +59,10 @@
   testRunner.log('Crafted frame context was created');
 
   testRunner.log('Remove crafted frame');
-  session.evaluate(`document.querySelector('#crafted-iframe').remove()`);
+  session.evaluate(`
+    document.querySelector('#crafted-iframe').remove();
+    GCController.collectAll();
+  `);
   executionContextId = (await dp.Runtime.onceExecutionContextDestroyed()).params.executionContextId;
   if (frameExecutionContextId !== executionContextId) {
     testRunner.fail(`Deleted frame had execution context with id = ${frameExecutionContextId}, but executionContext with id = ${executionContextId} was removed`);