Import Cobalt 20.master.0.234144 Includes the following patches: https://cobalt-review.googlesource.com/c/cobalt/+/5590 by n1214.hwang@samsung.com https://cobalt-review.googlesource.com/c/cobalt/+/5530 by errong.leng@samsung.com https://cobalt-review.googlesource.com/c/cobalt/+/5570 by devin.cai@mediatek.com
diff --git a/src/v8/test/debugger/BUILD.gn b/src/v8/test/debugger/BUILD.gn new file mode 100644 index 0000000..4a5b842 --- /dev/null +++ b/src/v8/test/debugger/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2018 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. + +group("v8_debugger") { + testonly = true + + data_deps = [ + "../..:d8", + "../../tools:v8_testrunner", + ] + + data = [ + "./", + ] +}
diff --git a/src/v8/test/debugger/debug/compiler/debug-catch-prediction.js b/src/v8/test/debugger/debug/compiler/debug-catch-prediction.js index 50fbf58..60ac95b 100644 --- a/src/v8/test/debugger/debug/compiler/debug-catch-prediction.js +++ b/src/v8/test/debugger/debug/compiler/debug-catch-prediction.js
@@ -34,6 +34,7 @@ return e; } } + %PrepareFunctionForOptimization(f); assertEquals("boom1", f(1)); assertEquals("boom2", f(2)); %OptimizeFunctionOnNextCall(f); @@ -51,6 +52,7 @@ return a + 10; } } + %PrepareFunctionForOptimization(f); assertEquals(11, f(1)); assertEquals(12, f(2)); %OptimizeFunctionOnNextCall(f); @@ -70,6 +72,7 @@ // Nothing. } } + %PrepareFunctionForOptimization(f); assertEquals("wosh11", f(1)); assertEquals("wosh22", f(2)); %OptimizeFunctionOnNextCall(f); @@ -91,6 +94,7 @@ return e + a; } } + %PrepareFunctionForOptimization(f); assertEquals("bang11", f(1)); assertEquals("bang22", f(2)); %OptimizeFunctionOnNextCall(f); @@ -112,6 +116,7 @@ return a + 10; } } + %PrepareFunctionForOptimization(f); assertEquals(11, f(1)); assertEquals(12, f(2)); %OptimizeFunctionOnNextCall(f); @@ -133,6 +138,7 @@ return a + 10; } } + %PrepareFunctionForOptimization(f); assertEquals(11, f(1)); assertEquals(12, f(2)); %OptimizeFunctionOnNextCall(f);
diff --git a/src/v8/test/debugger/debug/compiler/osr-typing-debug-change.js b/src/v8/test/debugger/debug/compiler/osr-typing-debug-change.js index 92eb899..e0346dd 100644 --- a/src/v8/test/debugger/debug/compiler/osr-typing-debug-change.js +++ b/src/v8/test/debugger/debug/compiler/osr-typing-debug-change.js
@@ -37,6 +37,7 @@ } return j; } +%PrepareFunctionForOptimization(ChangeSmiConstantAndOsr); var r1 = ChangeSmiConstantAndOsr(); if (changed) { assertEquals("result", r1); @@ -54,6 +55,7 @@ } return j; } +%PrepareFunctionForOptimization(ChangeFloatConstantAndOsr); var r2 = ChangeFloatConstantAndOsr(); if (changed) { assertEquals("result", r2); @@ -72,6 +74,7 @@ } return j; } +%PrepareFunctionForOptimization(ChangeFloatVarAndOsr); var r3 = ChangeFloatVarAndOsr(); if (changed) { assertEquals("result0.1", r3); @@ -105,6 +108,7 @@ } return j; } +%PrepareFunctionForOptimization(ChangeIntVarAndOsr); var r4 = ChangeIntVarAndOsr(); if (changed) {
diff --git a/src/v8/test/debugger/debug/debug-backtrace.js b/src/v8/test/debugger/debug/debug-backtrace.js index 63bbe10..79087d4 100644 --- a/src/v8/test/debugger/debug/debug-backtrace.js +++ b/src/v8/test/debugger/debug/debug-backtrace.js
@@ -42,8 +42,8 @@ Debug = debug.Debug -listenerCalled = false; -exception = false; +let listenerCalled = false; +let exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -82,7 +82,7 @@ listenerCalled = true; } } catch (e) { - exception = e; + exceptionThrown = true; }; }; @@ -94,5 +94,5 @@ g(); // Make sure that the debug event listener vas invoked. -assertFalse(exception, "exception in listener"); +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listenerCalled);
diff --git a/src/v8/test/debugger/debug/debug-bigint.js b/src/v8/test/debugger/debug/debug-bigint.js new file mode 100644 index 0000000..0ed09b0 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-bigint.js
@@ -0,0 +1,22 @@ +// Copyright 2018 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. + +Debug = debug.Debug +let exceptionThrown = false; + +Debug.setListener(function(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + const o = exec_state.frame(0).evaluate("42n", true); + assertEquals("bigint", o.type()); + assertFalse(o.isUndefined()); + assertEquals("bigint", typeof(o.value())); + assertEquals(42n, o.value()); + } catch (e) { + exceptionThrown = true; + }; +}); + +!function() { debugger; }(); +assertFalse(exceptionThrown, "exception in listener")
diff --git a/src/v8/test/debugger/debug/debug-break-class-fields.js b/src/v8/test/debugger/debug/debug-break-class-fields.js new file mode 100644 index 0000000..b6b9c93 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-break-class-fields.js
@@ -0,0 +1,139 @@ +// Copyright 2018 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. +// +// Flags: --harmony-public-fields --harmony-static-fields --allow-natives-syntax + +Debug = debug.Debug + +Debug.setListener(function() {}); + +class Y { + x = 1; + y = 2; + z = 3; +} + +var initializer = %GetInitializerFunction(Y); +var b1, b2, b3; + +// class Y { +// x = [B0]1; +// y = [B1]2; +// z = [B2]3; +// } +b1 = Debug.setBreakPoint(initializer, 0, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0); +Debug.clearBreakPoint(b1); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1); + +b2 = Debug.setBreakPoint(initializer, 1, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0); +Debug.clearBreakPoint(b2); +assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") === -1); + +b3 = Debug.setBreakPoint(initializer, 2, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") > 0); +Debug.clearBreakPoint(b3); +assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B0]3") === -1); + +b1 = Debug.setBreakPoint(initializer, 0, 0); +b2 = Debug.setBreakPoint(initializer, 1, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") > 0); +Debug.clearBreakPoint(b1); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1); +Debug.clearBreakPoint(b2); +assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B1]2;") === -1); + +b1 = Debug.setBreakPoint(initializer, 0, 0); +b3 = Debug.setBreakPoint(initializer, 2, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0); +Debug.clearBreakPoint(b1); +assertTrue(Debug.showBreakPoints(initializer).indexOf("x = [B0]1;") === -1); +Debug.clearBreakPoint(b3); +assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") === -1); + +b2 = Debug.setBreakPoint(initializer, 1, 0); +b3 = Debug.setBreakPoint(initializer, 2, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("y = [B0]2;") > 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("z = [B1]3") > 0); +Debug.clearBreakPoint(b2); +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. +// +// class X { +// [foo()] = [B0]1; +// [bar] = [B1]2; +// [baz] = [B2]foo(); +// } + +initializer = %GetInitializerFunction(X); +b1 = Debug.setBreakPoint(initializer, 0, 0); +assertTrue(Debug.showBreakPoints(initializer).indexOf("[foo()] = [B0]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); +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; + } +} + +b1 = Debug.setBreakPoint(t, 0, 0); +assertTrue(Debug.showBreakPoints(t).indexOf("[[B0]foo()] = 1;")> 0); +Debug.clearBreakPoint(b1); +assertTrue(Debug.showBreakPoints(initializer).indexOf("[[B0]foo()] = 1;") === -1);
diff --git a/src/v8/test/debugger/debug/debug-break-inline.js b/src/v8/test/debugger/debug/debug-break-inline.js index 18574ec..1b23f3d 100644 --- a/src/v8/test/debugger/debug/debug-break-inline.js +++ b/src/v8/test/debugger/debug/debug-break-inline.js
@@ -63,6 +63,7 @@ debugger; } +%PrepareFunctionForOptimization(f); f();f();f(); %OptimizeFunctionOnNextCall(f); f();
diff --git a/src/v8/test/debugger/debug/debug-break-native.js b/src/v8/test/debugger/debug/debug-break-native.js index 10ed405..68f9c9d 100644 --- a/src/v8/test/debugger/debug/debug-break-native.js +++ b/src/v8/test/debugger/debug/debug-break-native.js
@@ -26,7 +26,6 @@ } // break Debug.setBreakPoint(f, 0, 0); // break -Debug.scripts(); // break new Error("123").stack; // break Math.sin(0); // break
diff --git a/src/v8/test/debugger/debug/debug-break-return.js b/src/v8/test/debugger/debug/debug-break-return.js new file mode 100644 index 0000000..478162a --- /dev/null +++ b/src/v8/test/debugger/debug/debug-break-return.js
@@ -0,0 +1,40 @@ +// Copyright 2018 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. + +Debug = debug.Debug + +function foo(){} + +let breakpoint_count = 0; +let last_source_line = 0; +let last_source_column = 0; +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + ++breakpoint_count; + last_source_line = exec_state.frame(0).sourceLine(); + last_source_column = exec_state.frame(0).sourceColumn(); + } +}; + +Debug.setListener(listener); + +// Run without breakpoints. +foo(); +assertEquals(breakpoint_count, 0); + +// Run with breakpoint. +const breakpoint = Debug.setBreakPoint(foo, 0); +foo(); +assertEquals(breakpoint_count, 1); +assertEquals(last_source_line, 7); +assertEquals(last_source_column, 15); +foo(); +assertEquals(breakpoint_count, 2); +assertEquals(last_source_line, 7); +assertEquals(last_source_column, 15); + +// Run without breakpoints +Debug.clearBreakPoint(breakpoint); +foo(); +assertEquals(breakpoint_count, 2);
diff --git a/src/v8/test/debugger/debug/debug-clearbreakpoint.js b/src/v8/test/debugger/debug/debug-clearbreakpoint.js index 0c8267c..303eaf1 100644 --- a/src/v8/test/debugger/debug/debug-clearbreakpoint.js +++ b/src/v8/test/debugger/debug/debug-clearbreakpoint.js
@@ -28,8 +28,8 @@ Debug = debug.Debug // Simple function which stores the last debug event. -listenerComplete = false; -exception = false; +let listenerComplete = false; +let exceptionThrown = false; var breakpoint = -1; @@ -42,7 +42,7 @@ listenerComplete = true; } } catch (e) { - exception = e + exceptionThrown = true; }; }; @@ -57,4 +57,4 @@ // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete, "listener did not run to completion"); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener")
diff --git a/src/v8/test/debugger/debug/debug-compile-event.js b/src/v8/test/debugger/debug/debug-compile-event.js index 2e52609..6c92bd7 100644 --- a/src/v8/test/debugger/debug/debug-compile-event.js +++ b/src/v8/test/debugger/debug/debug-compile-event.js
@@ -27,7 +27,7 @@ Debug = debug.Debug -var exception = false; // Exception in debug event listener. +var exceptionThrown = false; // Exception in debug event listener. var after_compile_count = 0; var compile_error_count = 0; var current_source = ''; // Current source being compiled. @@ -85,7 +85,7 @@ } } } catch (e) { - exception = e + exceptionThrown = true; } }; @@ -110,7 +110,7 @@ } // Make sure that the debug event listener was invoked. -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener") // Number of before and after + error events should be the same. assertEquals(compile_error_count, 1);
diff --git a/src/v8/test/debugger/debug/debug-compile-optimized.js b/src/v8/test/debugger/debug/debug-compile-optimized.js index 33f199a..a48b250 100644 --- a/src/v8/test/debugger/debug/debug-compile-optimized.js +++ b/src/v8/test/debugger/debug/debug-compile-optimized.js
@@ -9,6 +9,7 @@ Debug.setListener(function() {}); function f() {} +%PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f); @@ -17,6 +18,7 @@ var bp = Debug.setBreakPoint(f); assertUnoptimized(f); +%PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f); @@ -24,6 +26,7 @@ assertUnoptimized(f); Debug.clearBreakPoint(bp); +%PrepareFunctionForOptimization(f); %OptimizeFunctionOnNextCall(f); f(); assertOptimized(f);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-arguments.js b/src/v8/test/debugger/debug/debug-evaluate-arguments.js index 8cf18d7..0c65a86 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-arguments.js +++ b/src/v8/test/debugger/debug/debug-evaluate-arguments.js
@@ -30,6 +30,7 @@ } return bar(1,2,a); } +%PrepareFunctionForOptimization(foo); listened = false; foo_expected = [3]; @@ -53,6 +54,7 @@ listened = false; foo_expected = [3,4,5]; bar_expected = [1,2,3]; +%PrepareFunctionForOptimization(foo); %OptimizeFunctionOnNextCall(foo); assertEquals(6, foo(3,4,5)); assertTrue(listened);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-bool-constructor.js b/src/v8/test/debugger/debug/debug-evaluate-bool-constructor.js index 83a0f06..2c30df9 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-bool-constructor.js +++ b/src/v8/test/debugger/debug/debug-evaluate-bool-constructor.js
@@ -29,7 +29,7 @@ Debug = debug.Debug var listenerComplete = false; -var exception = false; +var exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -43,7 +43,7 @@ } } catch (e) { print(e); - exception = e + exceptionThrown = true; }; }; @@ -60,5 +60,5 @@ // Make sure that the debug event listener vas invoked. -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener") assertTrue(listenerComplete, "listener did not run to completion");
diff --git a/src/v8/test/debugger/debug/debug-evaluate-dead-function-fails.js b/src/v8/test/debugger/debug/debug-evaluate-dead-function-fails.js new file mode 100644 index 0000000..ffa2916 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-evaluate-dead-function-fails.js
@@ -0,0 +1,35 @@ +// Copyright 2019 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. + +// Flags: --no-always-opt --no-stress-opt + +Debug = debug.Debug + +var exception = null; +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + // Evaluating the live function should succeed. + assertEquals(exec_state.frame(0).evaluate("live()").value(), 1); + // Evaluating the dead function should fail. + assertThrows(()=>exec_state.frame(0).evaluate("dead()"), ReferenceError); + } catch (e) { + exception = e; + print(e + e.stack); + } +} + +Debug.setListener(listener); + +(function() { + "use strict"; + function live() { return 1; } + function dead() { return 2; } + // Use 'foo' to make it non-dead. + live; + debugger; +})(); + +Debug.setListener(null); +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-function-var.js b/src/v8/test/debugger/debug/debug-evaluate-function-var.js new file mode 100644 index 0000000..42a6716 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-evaluate-function-var.js
@@ -0,0 +1,42 @@ +// Copyright 2019 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. + +Debug = debug.Debug +var exception = null; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + var frame = exec_state.frame(0); + try { + assertTrue(frame.evaluate("f").value().startsWith("function f()")); + } catch { + assertTrue(frame.sourceLineText().endsWith("throws")); + } + } + } catch(e) { + exception = e; + print(e, e.stack); + } +}; + +Debug.setListener(listener); + +(function f() { + f; + debugger; // works +})(); + +(function f() { + () => f; + debugger; // works +})(); + +(function f() { + debugger; // throws +})(); + +assertNull(exception); + +Debug.setListener(null);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-locals-optimized-double.js b/src/v8/test/debugger/debug/debug-evaluate-locals-optimized-double.js index 462194c..2160b97 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-locals-optimized-double.js +++ b/src/v8/test/debugger/debug/debug-evaluate-locals-optimized-double.js
@@ -30,7 +30,7 @@ Debug = debug.Debug var listenerComplete = false; -var exception = false; +var exceptionThrown = false; var testingConstructCall = false; @@ -127,10 +127,11 @@ listenerComplete = true; } } catch (e) { - exception = e.toString() + e.stack; + exceptionThrown = true; }; }; +%PrepareFunctionForOptimization(f); for (var i = 0; i < 4; i++) f(input.length - 1, 11.11, 12.12); %OptimizeFunctionOnNextCall(f); f(input.length - 1, 11.11, 12.12); @@ -191,7 +192,7 @@ new f(input.length - 1, 11.11, 12.12, ""); // Make sure that the debug event listener was invoked. -assertFalse(exception, "exception in listener " + exception) +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listenerComplete); //Throw away type information for next run.
diff --git a/src/v8/test/debugger/debug/debug-evaluate-locals-optimized.js b/src/v8/test/debugger/debug/debug-evaluate-locals-optimized.js index 93c90b5..057ceff 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-locals-optimized.js +++ b/src/v8/test/debugger/debug/debug-evaluate-locals-optimized.js
@@ -30,7 +30,7 @@ Debug = debug.Debug var listenerComplete = false; -var exception = false; +var exceptionThrown = false; var testingConstructCall = false; @@ -118,10 +118,11 @@ listenerComplete = true; } } catch (e) { - exception = e.toString() + e.stack; + exceptionThrown = true; }; }; +%PrepareFunctionForOptimization(f); for (var i = 0; i < 4; i++) f(expected.length - 1, 11, 12); %OptimizeFunctionOnNextCall(f); f(expected.length - 1, 11, 12); @@ -172,7 +173,7 @@ new f(expected.length - 1, 11, 12, 0); // Make sure that the debug event listener was invoked. -assertFalse(exception, "exception in listener " + exception) +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listenerComplete); // Throw away type information for next run.
diff --git a/src/v8/test/debugger/debug/debug-evaluate-locals.js b/src/v8/test/debugger/debug/debug-evaluate-locals.js index 0108acf..edc27e6 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-locals.js +++ b/src/v8/test/debugger/debug/debug-evaluate-locals.js
@@ -27,8 +27,8 @@ Debug = debug.Debug -listenerComplete = false; -exception = false; +let listenerComplete = false; +let exceptionThrown = false; function h() { @@ -132,7 +132,7 @@ listenerComplete = true; } } catch (e) { - exception = e; + exceptionThrown = true; print("Caught something. " + e + " " + e.stack); }; }; @@ -145,5 +145,5 @@ assertEquals("foobar", f_result); // Make sure that the debug event listener was invoked. -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listenerComplete);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-modify-catch-block-scope.js b/src/v8/test/debugger/debug/debug-evaluate-modify-catch-block-scope.js index 656399b..deb0d42 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-modify-catch-block-scope.js +++ b/src/v8/test/debugger/debug/debug-evaluate-modify-catch-block-scope.js
@@ -33,6 +33,8 @@ a *= 2; e *= 2; } + // Make sure bar is 'used' so that it is visible to the debugger. + bar; debugger; assertEquals(5, a); assertEquals(7, e);
diff --git a/src/v8/test/debugger/debug/debug-evaluate-with.js b/src/v8/test/debugger/debug/debug-evaluate-with.js index 260114d..640d050 100644 --- a/src/v8/test/debugger/debug/debug-evaluate-with.js +++ b/src/v8/test/debugger/debug/debug-evaluate-with.js
@@ -30,9 +30,9 @@ Debug = debug.Debug -listenerComplete = false; -exception = false; -breakPointCount = 0; +let listenerComplete = false; +let exceptionThrown = false; +let breakPointCount = 0; function listener(event, exec_state, event_data, data) { try { @@ -53,7 +53,7 @@ } } } catch (e) { - exception = e + exceptionThrown = true; }; }; @@ -79,4 +79,4 @@ // Make sure that the debug event listener vas invoked. assertEquals(3, breakPointCount); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener");
diff --git a/src/v8/test/debugger/debug/debug-evaluate.js b/src/v8/test/debugger/debug/debug-evaluate.js index 9328c32..922bad8 100644 --- a/src/v8/test/debugger/debug/debug-evaluate.js +++ b/src/v8/test/debugger/debug/debug-evaluate.js
@@ -27,8 +27,8 @@ Debug = debug.Debug -listenerComplete = false; -exception = false; +let listenerComplete = false; +let exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -51,7 +51,7 @@ listenerComplete = true; } } catch (e) { - exception = e + exceptionThrown = true; }; }; @@ -80,6 +80,6 @@ Debug.setBreakPoint(f, 2, 0); g(); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener"); // Make sure that the debug event listener vas invoked. assertTrue(listenerComplete, "listener did not run to completion");
diff --git a/src/v8/test/debugger/debug/debug-liveedit-1.js b/src/v8/test/debugger/debug/debug-liveedit-1.js index 950a2fa..a3fe1bf 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-1.js +++ b/src/v8/test/debugger/debug/debug-liveedit-1.js
@@ -25,6 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -34,13 +35,11 @@ assertEquals("Cat", ChooseAnimal()); -var script = Debug.findScript(ChooseAnimal); - var orig_animal = "Cat"; -var patch_pos = script.source.indexOf(orig_animal); var new_animal_patch = "Cap' + 'y' + 'bara"; +var new_source = + Debug.scriptSource(ChooseAnimal).replace(orig_animal, new_animal_patch); -var change_log = new Array(); -Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_animal.length, new_animal_patch, change_log); +%LiveEditPatchScript(ChooseAnimal, new_source); assertEquals("Capybara", ChooseAnimal());
diff --git a/src/v8/test/debugger/debug/debug-liveedit-2.js b/src/v8/test/debugger/debug/debug-liveedit-2.js index 408ee5a..f52ec26 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-2.js +++ b/src/v8/test/debugger/debug/debug-liveedit-2.js
@@ -25,8 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// Flags: --noalways-opt - +// Flags: --noalways-opt --allow-natives-syntax Debug = debug.Debug @@ -43,19 +42,12 @@ assertEquals("Cat", old_closure()); -var script = Debug.findScript(ChooseAnimal); - -var orig_animal = "'Cat'"; -var patch_pos = script.source.indexOf(orig_animal); -var new_animal_patch = "'Capybara' + p"; - // We patch innermost function "Chooser". // However, this does not actually patch existing "Chooser" instances, // because old value of parameter "p" was not saved. // Instead it patches ChooseAnimal. -var change_log = new Array(); -Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_animal.length, new_animal_patch, change_log); -print("Change log: " + JSON.stringify(change_log) + "\n"); +%LiveEditPatchScript( + ChooseAnimal, Debug.scriptSource(ChooseAnimal).replace("'Cat'", "'Capybara' + p")); var new_closure = ChooseAnimal(19); // New instance of closure is patched.
diff --git a/src/v8/test/debugger/debug/debug-liveedit-3.js b/src/v8/test/debugger/debug/debug-liveedit-3.js index c075453..790137d 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-3.js +++ b/src/v8/test/debugger/debug/debug-liveedit-3.js
@@ -30,6 +30,7 @@ // hasen't been changed. However actually function became one level more nested // and must be recompiled because it uses variable from outer scope. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -49,15 +50,11 @@ var z6 = Factory(6); assertEquals(8, z6()); -var script = Debug.findScript(Factory); +var new_source = Debug.scriptSource(Factory).replace( + function_z_text, + 'function Intermediate() {\nreturn (\n' + function_z_text + ')\n;\n}\n'); -var new_source = script.source.replace(function_z_text, "function Intermediate() {\nreturn (\n" + function_z_text + ")\n;\n}\n"); -print("new source: " + new_source); - -var change_log = new Array(); -var result = Debug.LiveEdit.SetScriptSource(script, new_source, false, change_log); -print("Result: " + JSON.stringify(result) + "\n"); -print("Change log: " + JSON.stringify(change_log) + "\n"); +%LiveEditPatchScript(Factory, new_source); assertEquals(8, z6());
diff --git a/src/v8/test/debugger/debug/debug-liveedit-4.js b/src/v8/test/debugger/debug/debug-liveedit-4.js index 0b94ece..eef7f20 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-4.js +++ b/src/v8/test/debugger/debug/debug-liveedit-4.js
@@ -31,6 +31,7 @@ // hasen't been changed. However actually function became one level more nested // and must be recompiled because it uses variable from outer scope. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -53,14 +54,10 @@ print(res); assertEquals('a,c', res); -var script = Debug.findScript(TestFunction); -var new_source = script.source.replace("2013", "b"); +var new_source = Debug.scriptSource(TestFunction).replace('2013', 'b'); print("new source: " + new_source); -var change_log = new Array(); -var result = Debug.LiveEdit.SetScriptSource(script, new_source, false, change_log); -print("Result: " + JSON.stringify(result) + "\n"); -print("Change log: " + JSON.stringify(change_log) + "\n"); +%LiveEditPatchScript(TestFunction, new_source); var res = TestFunction(); print(res);
diff --git a/src/v8/test/debugger/debug/debug-liveedit-arrow-function-at-start.js b/src/v8/test/debugger/debug/debug-liveedit-arrow-function-at-start.js new file mode 100644 index 0000000..ce0fe39 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-liveedit-arrow-function-at-start.js
@@ -0,0 +1,13 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax + +// ()=>42 will have the same start and end position as the top-level script. +var foo = eval("()=>{ return 42 }"); +assertEquals(42, foo()); + +%LiveEditPatchScript(foo, "()=>{ return 13 }"); + +assertEquals(13, foo());
diff --git a/src/v8/test/debugger/debug/debug-liveedit-check-stack.js b/src/v8/test/debugger/debug/debug-liveedit-check-stack.js index e016a53..e2e9c64 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-check-stack.js +++ b/src/v8/test/debugger/debug/debug-liveedit-check-stack.js
@@ -25,6 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -33,35 +34,26 @@ function TestBase(name) { print("TestBase constructor: " + name); - this.ChooseAnimal = eval( - "/* " + unique_id + "*/\n" + - "(function ChooseAnimal(callback) {\n " + - " callback();\n" + - " return 'Cat';\n" + - "})\n" - ); + const original_source = '/* ' + unique_id + '*/\n' + + '(function ChooseAnimal(callback) {\n ' + + ' callback();\n' + + ' return \'Cat\';\n' + + '})\n'; + const updated_source = original_source.replace('\'Cat\'', '\'Capybara\''); + + this.ChooseAnimal = eval(original_source); // Prevents eval script caching. unique_id++; - var script = Debug.findScript(this.ChooseAnimal); - - var orig_animal = "'Cat'"; - var patch_pos = script.source.indexOf(orig_animal); - var new_animal_patch = "'Capybara'"; + const func = this.ChooseAnimal; var got_exception = false; var successfully_changed = false; // Should be called from Debug context. - this.ScriptChanger = function() { + this.ScriptChanger = () => { assertEquals(false, successfully_changed, "applying patch second time"); - // Runs in debugger context. - var change_log = new Array(); - try { - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_animal.length, new_animal_patch, change_log); - } finally { - print("Change log: " + JSON.stringify(change_log) + "\n"); - } + %LiveEditPatchScript(func, updated_source); successfully_changed = true; }; } @@ -74,7 +66,7 @@ try { f(); } catch (e) { - if (e instanceof Debug.LiveEdit.Failure) { + if (e.startsWith('LiveEdit failed')) { holder[0] = e; } else { throw e;
diff --git a/src/v8/test/debugger/debug/debug-liveedit-compile-error.js b/src/v8/test/debugger/debug/debug-liveedit-compile-error.js index 24068eb..33953a3 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-compile-error.js +++ b/src/v8/test/debugger/debug/debug-liveedit-compile-error.js
@@ -25,6 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -34,23 +35,16 @@ assertEquals("Cat", ChooseAnimal()); -var script = Debug.findScript(ChooseAnimal); +var new_source = + Debug.scriptSource(ChooseAnimal).replace('Cat', 'Cap\' + ) + \'bara'); +print('new source: ' + new_source); -var orig_animal = "Cat"; -var patch_pos = script.source.indexOf(orig_animal); -var new_animal_patch = "Cap' + ) + 'bara"; - -var change_log = new Array(); var caught_exception = null; try { - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, - orig_animal.length, new_animal_patch, change_log); + %LiveEditPatchScript(ChooseAnimal, new_source); } catch (e) { caught_exception = e; } assertNotNull(caught_exception); -assertEquals("Unexpected token )", - caught_exception.details.syntaxErrorMessage); - -assertEquals(2, caught_exception.details.position.start.line); +assertEquals('LiveEdit failed: COMPILE_ERROR', caught_exception);
diff --git a/src/v8/test/debugger/debug/debug-liveedit-double-call.js b/src/v8/test/debugger/debug/debug-liveedit-double-call.js index 77d800e..1de6bd3 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-double-call.js +++ b/src/v8/test/debugger/debug/debug-liveedit-double-call.js
@@ -78,8 +78,6 @@ var test_fun = eval(script_text_generator.get()); - var script = Debug.findScript(test_fun); - var scenario_pos = 0; function DebuggerStatementHandler() { @@ -92,8 +90,7 @@ } script_text_generator.change(change_var); try { - Debug.LiveEdit.SetScriptSource(script, script_text_generator.get(), - false, []); + %LiveEditPatchScript(test_fun, script_text_generator.get()) } catch (e) { print("LiveEdit exception: " + e); throw e;
diff --git a/src/v8/test/debugger/debug/debug-liveedit-exceptions.js b/src/v8/test/debugger/debug/debug-liveedit-exceptions.js index 36463b3..091f1af 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-exceptions.js +++ b/src/v8/test/debugger/debug/debug-liveedit-exceptions.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. +// Flags: --allow-natives-syntax Debug = debug.Debug - function BestEditor() { throw 'Emacs'; } @@ -37,11 +37,8 @@ }; function Replace(fun, original, patch) { - var script = Debug.findScript(fun); if (fun.toString().indexOf(original) < 0) return; - var patch_pos = script.source.indexOf(original); - var change_log = []; - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, original.length, patch, change_log); + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); } Debug.setListener(listener);
diff --git a/src/v8/test/debugger/debug/debug-liveedit-inline.js b/src/v8/test/debugger/debug/debug-liveedit-inline.js index 4d20991..1e0671e 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-inline.js +++ b/src/v8/test/debugger/debug/debug-liveedit-inline.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 -// Flags: --allow-natives-syntax --enable-inspector +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -12,19 +12,16 @@ function foo() { return ChooseAnimal() } +%PrepareFunctionForOptimization(foo); assertEquals("Cat", foo()); - %OptimizeFunctionOnNextCall(foo); +%OptimizeFunctionOnNextCall(foo); foo(); -var script = Debug.findScript(ChooseAnimal); +var new_source = + Debug.scriptSource(ChooseAnimal).replace('Cat', "Cap' + 'y' + 'bara"); +print('new source: ' + new_source); -var orig_animal = "Cat"; -var patch_pos = script.source.indexOf(orig_animal); -var new_animal_patch = "Cap' + 'y' + 'bara"; - -var change_log = new Array(); - -Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_animal.length, new_animal_patch, change_log); +%LiveEditPatchScript(ChooseAnimal, new_source); assertEquals("Capybara", foo());
diff --git a/src/v8/test/debugger/debug/debug-liveedit-literals.js b/src/v8/test/debugger/debug/debug-liveedit-literals.js index 08edec3..65ba12c 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-literals.js +++ b/src/v8/test/debugger/debug/debug-liveedit-literals.js
@@ -25,6 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -46,14 +47,9 @@ assertEquals("Cat", ChooseAnimalArray[i]()); } - var script = Debug.findScript(ChooseAnimalArray[0]); - - var patch_pos = script.source.indexOf(old_expression); - var new_animal_patch = new_expression; - - var change_log = new Array(); - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, - old_expression.length, new_expression, change_log); + var new_source = + Debug.scriptSource(ChooseAnimalArray[0]).replace(old_expression, new_expression); + %LiveEditPatchScript(ChooseAnimalArray[0], new_source); for (var i = 0; i < ChooseAnimalArray.length; i++) { assertEquals("Capybara", ChooseAnimalArray[i]());
diff --git a/src/v8/test/debugger/debug/debug-liveedit-newsource.js b/src/v8/test/debugger/debug/debug-liveedit-newsource.js index e6f55bb..08b9017 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-newsource.js +++ b/src/v8/test/debugger/debug/debug-liveedit-newsource.js
@@ -25,6 +25,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// Flags: --allow-natives-syntax Debug = debug.Debug @@ -47,9 +48,7 @@ assertEquals("Cat", ChooseAnimal()); assertEquals(25, something1); -var script = Debug.findScript(ChooseAnimal); - -var new_source = script.source.replace("Cat", "Cap' + 'yb' + 'ara"); +var new_source = Debug.scriptSource(ChooseAnimal).replace("Cat", "Cap' + 'yb' + 'ara"); var new_source = new_source.replace("25", "26"); var new_source = new_source.replace("Help", "Hello"); var new_source = new_source.replace("17", "18"); @@ -62,10 +61,7 @@ var new_source = new_source.replace("// Array", "Array"); print("new source: " + new_source); -var change_log = new Array(); -var result = Debug.LiveEdit.SetScriptSource(script, new_source, false, change_log); -print("Result: " + JSON.stringify(result) + "\n"); -print("Change log: " + JSON.stringify(change_log) + "\n"); +%LiveEditPatchScript(ChooseAnimal, new_source); assertEquals("Capybara", ChooseAnimal()); // Global variable do not get changed (without restarting script).
diff --git a/src/v8/test/debugger/debug/debug-liveedit-patch-positions-replace.js b/src/v8/test/debugger/debug/debug-liveedit-patch-positions-replace.js index 374ffde..21d2d36 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-patch-positions-replace.js +++ b/src/v8/test/debugger/debug/debug-liveedit-patch-positions-replace.js
@@ -34,6 +34,7 @@ // change they are 114 characters away from each other. New instance of Code is // required when those numbers cross the border value of 64 (in any direction). +// Flags: --allow-natives-syntax Debug = debug.Debug eval( @@ -46,19 +47,13 @@ "}" ); -var script = Debug.findScript(BeingReplaced); - -var orig_body = "{}"; -var patch_pos = script.source.indexOf(orig_body); -// Line long enough to change rinfo encoding. -var new_body_patch = "{return 'Capybara';" + - " " + - "}"; - -var change_log = new Array(); function Changer() { - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_body.length, new_body_patch, change_log); - print("Change log: " + JSON.stringify(change_log) + "\n"); + // Line long enough to change rinfo encoding. + var new_source = + Debug.scriptSource(BeingReplaced).replace("{}", "{return 'Capybara';" + + " " + + "}"); + %LiveEditPatchScript(BeingReplaced, new_source); } function NoOp() {
diff --git a/src/v8/test/debugger/debug/debug-liveedit-recursion.js b/src/v8/test/debugger/debug/debug-liveedit-recursion.js new file mode 100644 index 0000000..6328a9b --- /dev/null +++ b/src/v8/test/debugger/debug/debug-liveedit-recursion.js
@@ -0,0 +1,40 @@ +// Copyright 2018 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. + +// Flags: --allow-natives-syntax + +Debug = debug.Debug; + +function test(i) { + if (i == 3) { + return (function* gen() { yield test(i - 1); })().next().value; + } else if (i > 1) { + return test(i - 1); + } else { + debugger; + return 5; + } +} + +let patch = null, exception = null; + +Debug.setListener(listener); +patch = ['return 5', 'return 3']; +assertEquals(3, test(2)); // no running generator +patch = ['return 3', 'return -1']; +assertEquals(3, test(3)); // there is running generator +assertEquals(exception, + 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME'); +Debug.setListener(null); + +function listener(event) { + if (event != Debug.DebugEvent.Break || !patch) return; + try { + %LiveEditPatchScript(test, + Debug.scriptSource(test).replace(patch[0], patch[1])); + } catch (e) { + exception = e; + } + patch = null; +}
diff --git a/src/v8/test/debugger/debug/debug-liveedit-replace-code.js b/src/v8/test/debugger/debug/debug-liveedit-replace-code.js index a3b83bb..c517c67 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-replace-code.js +++ b/src/v8/test/debugger/debug/debug-liveedit-replace-code.js
@@ -2,25 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Flags: --allow-natives-syntax + Debug = debug.Debug var counter = 0; var exception = null; - function f() { if (++counter > 5) return; debugger; return counter; -} +}; function listener(event, exec_state, event_data, data) { if (event != Debug.DebugEvent.Break) return; try { - var script = Debug.findScript(f); var original = 'debugger;'; var patch = 'debugger;\n'; - var position = script.source.indexOf(original); - Debug.LiveEdit.TestApi.ApplySingleChunkPatch( - script, position, original.length, patch, []); + %LiveEditPatchScript(f, Debug.scriptSource(f).replace(original, patch)); } catch (e) { exception = e; }
diff --git a/src/v8/test/debugger/debug/debug-liveedit-stepin.js b/src/v8/test/debugger/debug/debug-liveedit-stepin.js index f96a079..10264dd 100644 --- a/src/v8/test/debugger/debug/debug-liveedit-stepin.js +++ b/src/v8/test/debugger/debug/debug-liveedit-stepin.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. +// Flags: --allow-natives-syntax Debug = debug.Debug - function BestEditor() { return 'Emacs'; } @@ -39,11 +39,8 @@ }; function Replace(fun, original, patch) { - var script = Debug.findScript(fun); if (fun.toString().indexOf(original) < 0) return; - var patch_pos = script.source.indexOf(original); - var change_log = []; - Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, original.length, patch, change_log); + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); } Debug.setListener(listener); @@ -56,7 +53,6 @@ assertNull(exception); assertEquals(["Emacs", "Eclipse", "Vim"], results); -print(JSON.stringify(log, 1)); assertEquals([ "debugger;", "results.push(BestEditor());",
diff --git a/src/v8/test/debugger/debug/debug-materialized.js b/src/v8/test/debugger/debug/debug-materialized.js index dd22e1e..857bbb8 100644 --- a/src/v8/test/debugger/debug/debug-materialized.js +++ b/src/v8/test/debugger/debug/debug-materialized.js
@@ -18,6 +18,8 @@ return t.a; } +%PrepareFunctionForOptimization(foo); +%PrepareFunctionForOptimization(bar); foo(1); foo(1); bar(1);
diff --git a/src/v8/test/debugger/debug/debug-modules-set-variable-value.mjs b/src/v8/test/debugger/debug/debug-modules-set-variable-value.mjs new file mode 100644 index 0000000..368ab49 --- /dev/null +++ b/src/v8/test/debugger/debug/debug-modules-set-variable-value.mjs
@@ -0,0 +1,376 @@ +// Copyright 2016 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. +// Flags: --no-always-opt --no-opt + +// The first part of this file is copied over from debug-set-variable-value.js +// (a few tests were removed because they make no sense for modules). The second +// part is new. + +var Debug = debug.Debug; + +// Accepts a function/closure 'fun' that must have a debugger statement inside. +// A variable 'variable_name' must be initialized before debugger statement +// and returned after the statement. The test will alter variable value when +// on debugger statement and check that returned value reflects the change. +function RunPauseTest(scope_number, expected_old_result, variable_name, + new_value, expected_new_result, fun) { + var actual_old_result = fun(); + assertEquals(expected_old_result, actual_old_result); + + var listener_delegate; + var listener_called = false; + var exception = null; + + function listener_delegate(exec_state) { + var scope = exec_state.frame(0).scope(scope_number); + scope.setVariableValue(variable_name, new_value); + } + + function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + listener_called = true; + listener_delegate(exec_state); + } + } catch (e) { + exception = e; + } + } + + // Add the debug event listener. + Debug.setListener(listener); + + var actual_new_result; + try { + actual_new_result = fun(); + } finally { + Debug.setListener(null); + } + + if (exception != null) { + assertUnreachable("Exception in listener\n" + exception.stack); + } + assertTrue(listener_called); + + assertEquals(expected_new_result, actual_new_result); +} + + +function ClosureTestCase(scope_index, old_result, variable_name, new_value, + new_result, success_expected, factory) { + this.scope_index_ = scope_index; + this.old_result_ = old_result; + this.variable_name_ = variable_name; + this.new_value_ = new_value; + this.new_result_ = new_result; + this.success_expected_ = success_expected; + this.factory_ = factory; +} + +ClosureTestCase.prototype.run_pause_test = function() { + var th = this; + var fun = this.factory_(true); + this.run_and_catch_(function() { + RunPauseTest(th.scope_index_ + 1, th.old_result_, th.variable_name_, + th.new_value_, th.new_result_, fun); + }); +} + +ClosureTestCase.prototype.run_and_catch_ = function(runnable) { + if (this.success_expected_) { + runnable(); + } else { + assertThrows(runnable); + } +} + + +// Test scopes visible from closures. + +var closure_test_cases = [ + new ClosureTestCase(0, 'cat', 'v1', 5, 5, true, + function Factory(debug_stop) { + var v1 = 'cat'; + return function() { + if (debug_stop) debugger; + return v1; + } + }), + + new ClosureTestCase(0, 4, 't', 7, 9, true, function Factory(debug_stop) { + var t = 2; + var r = eval("t"); + return function() { + if (debug_stop) debugger; + return r + t; + } + }), + + new ClosureTestCase(0, 6, 't', 10, 13, true, function Factory(debug_stop) { + var t = 2; + var r = eval("t = 3"); + return function() { + if (debug_stop) debugger; + return r + t; + } + }), + + new ClosureTestCase(2, 'capybara', 'foo', 77, 77, true, + function Factory(debug_stop) { + var foo = "capybara"; + return (function() { + var bar = "fish"; + try { + throw {name: "test exception"}; + } catch (e) { + return function() { + if (debug_stop) debugger; + bar = "beast"; + return foo; + } + } + })(); + }), + + new ClosureTestCase(0, 'AlphaBeta', 'eee', 5, '5Beta', true, + function Factory(debug_stop) { + var foo = "Beta"; + return (function() { + var bar = "fish"; + try { + throw "Alpha"; + } catch (eee) { + return function() { + if (debug_stop) debugger; + return eee + foo; + } + } + })(); + }) +]; + +for (var i = 0; i < closure_test_cases.length; i++) { + closure_test_cases[i].run_pause_test(); +} + + +// Test local scope. + +RunPauseTest(0, 'HelloYou', 'u', 'We', 'HelloWe', (function Factory() { + return function() { + var u = "You"; + var v = "Hello"; + debugger; + return v + u; + } +})()); + +RunPauseTest(0, 'Helloworld', 'p', 'GoodBye', 'HelloGoodBye', + (function Factory() { + function H(p) { + var v = "Hello"; + debugger; + return v + p; + } + return function() { + return H("world"); + } +})()); + +RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() { + return function() { + var v1 = 'cat'; + eval("v1 = 'mouse'"); + debugger; + return v1; + } +})()); + +// Check that we correctly update local variable that +// is referenced from an inner closure. +RunPauseTest(0, 'Blue', 'v', 'Green', 'Green', (function Factory() { + return function() { + function A() { + var v = "Blue"; + function Inner() { + return void v; + } + debugger; + return v; + } + return A(); + } +})()); + +// Check that we correctly update parameter, that is known to be stored +// both on stack and in heap. +RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() { + return function() { + function A(p) { + function Inner() { + return void p; + } + debugger; + return p; + } + return A(5); + } +})()); + + +//////////////////////////////////////////////////////////////////////////////// +// From here on we test the module scope. +//////////////////////////////////////////////////////////////////////////////// + + +// Non-existing variable. +{ + let exception; + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + try { + module_scope.setVariableValue('spargel', 42); + } catch(e) { exception = e; } + } + } + + Debug.setListener(listener); + assertThrows(() => spargel, ReferenceError); + debugger; + assertThrows(() => spargel, ReferenceError); + assertTrue(exception !== undefined); +} + + +// Local (non-exported) variable. +let salat = 12; +{ + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + module_scope.setVariableValue('salat', 42); + } + } + + Debug.setListener(listener); + assertEquals(12, salat); + debugger; + assertEquals(42, salat); +} + + +// Local (non-exported) variable, nested access. +let salad = 12; +{ + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let scope_count = exec_state.frame().scopeCount(); + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + module_scope.setVariableValue('salad', 42); + } + } + + Debug.setListener(listener); + function foo() { + assertEquals(12, salad); + debugger; + assertEquals(42, salad); + }; + foo(); +} + + +// Exported variable. +export let salami = 1; +{ + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + module_scope.setVariableValue('salami', 2); + } + } + + Debug.setListener(listener); + assertEquals(1, salami); + debugger; + assertEquals(2, salami); +} + + +// Exported variable, nested access. +export let ham = 1; +{ + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let scope_count = exec_state.frame().scopeCount(); + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + module_scope.setVariableValue('ham', 2); + } + } + + Debug.setListener(listener); + function foo() { + assertEquals(1, ham); + debugger; + assertEquals(2, ham); + }; + foo(); +} + + +// Imported variable. Setting is currently not supported. +import { salami as wurst } from "./debug-modules-set-variable-value.mjs"; +{ + let exception; + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let module_scope = exec_state.frame().scope(1); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + try { + module_scope.setVariableValue('wurst', 3); + } catch(e) { exception = e; } + } + } + + Debug.setListener(listener); + assertEquals(2, wurst); + debugger; + assertEquals(2, wurst); + assertTrue(exception !== undefined); +} + + +// Imported variable, nested access. Setting is currently not supported. +import { salami as wurstl } from "./debug-modules-set-variable-value.mjs"; +{ + let exception; + function listener(event, exec_state) { + if (event == Debug.DebugEvent.Break) { + let scope_count = exec_state.frame().scopeCount(); + let module_scope = exec_state.frame().scope(2); + assertEquals(debug.ScopeType.Module, module_scope.scopeType()); + try { + module_scope.setVariableValue('wurstl', 3); + } catch(e) { exception = e; } + } + } + + Debug.setListener(listener); + function foo() { + assertEquals(2, wurstl); + debugger; + assertEquals(2, wurstl); + assertTrue(exception !== undefined); + }; + foo(); +} + + +Debug.setListener(null);
diff --git a/src/v8/test/debugger/debug/debug-optimize.js b/src/v8/test/debugger/debug/debug-optimize.js index f296816..1945683 100644 --- a/src/v8/test/debugger/debug/debug-optimize.js +++ b/src/v8/test/debugger/debug/debug-optimize.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. -// Flags: --opt --no-always-opt +// Flags: --opt --no-always-opt --turbo-inlining var Debug = debug.Debug; @@ -24,6 +24,7 @@ function optimize(f) { + %PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f);
diff --git a/src/v8/test/debugger/debug/debug-return-value.js b/src/v8/test/debugger/debug/debug-return-value.js index 77717ce..4e8db7e 100644 --- a/src/v8/test/debugger/debug/debug-return-value.js +++ b/src/v8/test/debugger/debug/debug-return-value.js
@@ -27,12 +27,12 @@ Debug = debug.Debug -listener_complete = false; -exception = false; -break_count = 0; -expected_return_value = 0; -expected_source_position = []; -debugger_source_position = 0; +let listener_complete = false; +let exceptionThrown = false; +let break_count = 0; +let expected_return_value = 0; +let expected_source_position = []; +let debugger_source_position = 0; // Listener which expects to do four steps to reach returning from the function. function listener(event, exec_state, event_data, data) { @@ -72,7 +72,7 @@ } } } catch (e) { - exception = e + exceptionThrown = true; print(e + e.stack) }; }; @@ -93,7 +93,7 @@ expected_source_position = [10, 38, 47]; listener_complete = false; f(); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listener_complete); assertEquals(4, break_count); @@ -102,7 +102,7 @@ expected_source_position = [10, 19, 28]; listener_complete = false; f(true); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listener_complete); assertEquals(4, break_count); @@ -111,6 +111,6 @@ expected_source_position = [10, 38, 47]; listener_complete = false; f(false); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener"); assertTrue(listener_complete); assertEquals(4, break_count);
diff --git a/src/v8/test/debugger/debug/debug-scopes-suspended-generators.js b/src/v8/test/debugger/debug/debug-scopes-suspended-generators.js index 2d9d253..8d09e9c 100644 --- a/src/v8/test/debugger/debug/debug-scopes-suspended-generators.js +++ b/src/v8/test/debugger/debug/debug-scopes-suspended-generators.js
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Flags: --no-analyze-environment-liveness + // The functions used for testing backtraces. They are at the top to make the // testing of source line/column easier.
diff --git a/src/v8/test/debugger/debug/debug-scopes.js b/src/v8/test/debugger/debug/debug-scopes.js index 6f01cec..08e8d36 100644 --- a/src/v8/test/debugger/debug/debug-scopes.js +++ b/src/v8/test/debugger/debug/debug-scopes.js
@@ -123,7 +123,7 @@ assertEquals(names.length, all_scopes.length, "FrameMirror.allScopes length"); for (var i = 0; i < names.length; i++) { var scope = exec_state.frame().scope(i); - assertEquals(names[i], scope.details().name()) + // assertEquals(names[i], scope.details().name()) } } @@ -175,8 +175,8 @@ if (!position) continue; - assertEquals(position.start, scope.details().startPosition()) - assertEquals(position.end, scope.details().endPosition()) + // assertEquals(position.start, scope.details().startPosition()) + // assertEquals(position.end, scope.details().endPosition()) } } @@ -457,6 +457,7 @@ debugger; } } +%PrepareFunctionForOptimization(with_7); listener_delegate = function(exec_state) { CheckScopeChain([debug.ScopeType.With, @@ -722,6 +723,89 @@ EndTest(); +// Closure with inferred name. +BeginTest("Closure with Inferred Name 1"); + +function closure_1_inferred_name(a) { + let foo = {}; + foo.bar = function() { + debugger; + return a; + }; + return foo.bar; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1}, 1, exec_state); + CheckScopeChainNames(["foo.bar", "closure_1_inferred_name", undefined, + undefined], exec_state); +}; +closure_1_inferred_name(1)(); +EndTest(); + +// Closure with nested inferred name. +BeginTest("Closure with Inferred Name 2"); + +function closure_2_inferred_name(a) { + let foo = {}; + function FooBar(b) { + foo.baz = function() { + debugger; + return a+b; + } + return foo.baz; + }; + return FooBar; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Closure, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({b:0x1235}, 1, exec_state); + CheckScopeContent({a:0x1234}, 2, exec_state); + CheckScopeChainNames(["FooBar.foo.baz", "FooBar", "closure_2_inferred_name", + undefined, undefined], exec_state); +}; +closure_2_inferred_name(0x1234)(0x1235)(); +EndTest(); + + +// Closure with nested inferred name. +BeginTest("Closure with Inferred Name 3"); + +function closure_3_inferred_name(a) { + let foo = {}; + foo.bar = function(b) { + foo.baz = function() { + debugger; + return a+b; + } + return foo.baz; + }; + return foo.bar; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Closure, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({b:0x1235}, 1, exec_state); + CheckScopeContent({a:0x1234}, 2, exec_state); + CheckScopeChainNames(["foo.baz", "foo.bar", "closure_3_inferred_name", + undefined, undefined], exec_state); +}; +closure_3_inferred_name(0x1234)(0x1235)(); +EndTest(); + BeginTest("Closure passed to optimized Array.prototype.forEach"); function closure_10(a) { var x = a + 2; @@ -742,6 +826,7 @@ CheckScopeChainNames( ["closure_11", "closure_10", undefined, undefined], exec_state); }; +%PrepareFunctionForOptimization(closure_10); begin_test_count++; closure_10(5); end_test_count++; begin_test_count++; closure_10(5); end_test_count++; %OptimizeFunctionOnNextCall(closure_10); @@ -1069,6 +1154,7 @@ debugger; } }; +%PrepareFunctionForOptimization(catch_block_7); listener_delegate = function(exec_state) {
diff --git a/src/v8/test/debugger/debug/debug-step-end-of-script.js b/src/v8/test/debugger/debug/debug-step-end-of-script.js index 92a381e..ec5eb37 100644 --- a/src/v8/test/debugger/debug/debug-step-end-of-script.js +++ b/src/v8/test/debugger/debug/debug-step-end-of-script.js
@@ -4,7 +4,7 @@ var Debug = debug.Debug; -var expected = ["debugger;", "debugger;"]; +var expected = ["debugger;", ""]; function listener(event, exec_state, event_data, data) { if (event != Debug.DebugEvent.Break) return;
diff --git a/src/v8/test/debugger/debug/debug-step-microtask.js b/src/v8/test/debugger/debug/debug-step-microtask.js index 258f235..633bac8 100644 --- a/src/v8/test/debugger/debug/debug-step-microtask.js +++ b/src/v8/test/debugger/debug/debug-step-microtask.js
@@ -44,7 +44,7 @@ Debug.setListener(null); assertNull(exception); var expectation = - ["debugger;","debugger;"," print(1);","}"," return 2;"," return 2;", + ["debugger;",""," print(1);","}"," return 2;"," return 2;", " throw new Error();"," print(3);","} // STOP"]; assertEquals(log, expectation); });
diff --git a/src/v8/test/debugger/debug/debug-step-turbofan.js b/src/v8/test/debugger/debug/debug-step-turbofan.js index a40114b..0ffc2c8 100644 --- a/src/v8/test/debugger/debug/debug-step-turbofan.js +++ b/src/v8/test/debugger/debug/debug-step-turbofan.js
@@ -44,6 +44,7 @@ } } +%PrepareFunctionForOptimization(g); f(0); f(0); %OptimizeFunctionOnNextCall(g);
diff --git a/src/v8/test/debugger/debug/deserialize-script-id.js b/src/v8/test/debugger/debug/deserialize-script-id.js new file mode 100644 index 0000000..680f60d --- /dev/null +++ b/src/v8/test/debugger/debug/deserialize-script-id.js
@@ -0,0 +1,15 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax --cache=code +// Test that script ids are unique and we found the correct ones. + +var Debug = debug.Debug; +Debug.setListener(function(){}); + +var ids = %DebugGetLoadedScriptIds(); +ids.sort((a, b) => a - b); +ids.reduce((prev, cur) => assertTrue(prev === undefined || prev != cur)); + +Debug.setListener(null);
diff --git a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-1.js b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-1.js index 40dc816b..ea8765c 100644 --- a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-1.js +++ b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-1.js
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - // Test that live-editing a frame that uses new.target fails. +// Flags: --allow-natives-syntax Debug = debug.Debug var calls = 0; @@ -43,16 +43,10 @@ function Replace(fun, original, patch) { ExecuteInDebugContext(function() { - var change_log = []; try { - var script = Debug.findScript(fun); - var patch_pos = script.source.indexOf(original); - Debug.LiveEdit.TestApi.ApplySingleChunkPatch( - script, patch_pos, original.length, patch, change_log); + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); } catch (e) { - assertEquals("BLOCKED_NO_NEW_TARGET_ON_RESTART", - change_log[0].functions_on_stack[0].replace_problem); - assertInstanceof(e, Debug.LiveEdit.Failure); + assertEquals(e, 'LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME'); exceptions++; } });
diff --git a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-2.js b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-2.js index 764c57c..63b5fac 100644 --- a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-2.js +++ b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-2.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. - +// Flags: --allow-natives-syntax // Test that live-editing a frame to introduce new.target fails. Debug = debug.Debug @@ -40,16 +40,10 @@ function Replace(fun, original, patch) { ExecuteInDebugContext(function() { - var change_log = []; try { - var script = Debug.findScript(fun); - var patch_pos = script.source.indexOf(original); - Debug.LiveEdit.TestApi.ApplySingleChunkPatch( - script, patch_pos, original.length, patch, change_log); + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); } catch (e) { - assertEquals("BLOCKED_NO_NEW_TARGET_ON_RESTART", - change_log[0].functions_on_stack[0].replace_problem); - assertInstanceof(e, Debug.LiveEdit.Failure); + assertEquals(e, 'LiveEdit failed: BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME'); exceptions++; } });
diff --git a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-3.js b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-3.js index 60ec9a7..c607290 100644 --- a/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-3.js +++ b/src/v8/test/debugger/debug/es6/debug-liveedit-new-target-3.js
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - // Test that live-editing a frame above one that uses new.target succeeds. +// Flags: --allow-natives-syntax -Debug = debug.Debug +Debug = debug.Debug; var wrapper_calls = 0; var construct_calls = 0; var exceptions = 0; @@ -47,10 +47,7 @@ ExecuteInDebugContext(function() { var change_log = []; try { - var script = Debug.findScript(fun); - var patch_pos = script.source.indexOf(original); - Debug.LiveEdit.TestApi.ApplySingleChunkPatch( - script, patch_pos, original.length, patch, change_log); + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(original, patch)); } catch (e) { exceptions++; }
diff --git a/src/v8/test/debugger/debug/es6/debug-promises/evaluate-across-microtasks.js b/src/v8/test/debugger/debug/es6/debug-promises/evaluate-across-microtasks.js index 71b0747..ec3555d 100644 --- a/src/v8/test/debugger/debug/es6/debug-promises/evaluate-across-microtasks.js +++ b/src/v8/test/debugger/debug/es6/debug-promises/evaluate-across-microtasks.js
@@ -51,7 +51,7 @@ // Make sure that the debug event listener was invoked. assertTrue(listenerComplete); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); var expectation = [ "[0] debugger", "[1] start", "[1] then 1",
diff --git a/src/v8/test/debugger/debug/es6/debug-promises/proxy-as-promise.js b/src/v8/test/debugger/debug/es6/debug-promises/proxy-as-promise.js new file mode 100644 index 0000000..431837c --- /dev/null +++ b/src/v8/test/debugger/debug/es6/debug-promises/proxy-as-promise.js
@@ -0,0 +1,42 @@ +// Copyright 2018 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. + + +// Test debug events when we listen to all exceptions and +// there is a catch handler for the exception thrown in a Promise. +// We expect a normal Exception debug event to be triggered. + +Debug = debug.Debug; + +var expected_events = 1; +var log = []; + + +class P extends Promise { + constructor(...args) { + super(...args); + return new Proxy(this, { + get(target, property, receiver) { + if (property in target) { + return Reflect.get(target, property, receiver); + } else { + return (...args) => + new Promise((resolve, reject) => + target.then(v => resolve(v[property](...args))) + .catch(reject) + ); + } + } + }); + } +} + +P.resolve({doStuff(){log.push(1)}}).doStuff() + +function listener(event, exec_state, event_data, data) {} + +Debug.setBreakOnUncaughtException(); +Debug.setListener(listener); + +%PerformMicrotaskCheckpoint();
diff --git a/src/v8/test/debugger/debug/es6/debug-promises/reject-in-constructor-opt.js b/src/v8/test/debugger/debug/es6/debug-promises/reject-in-constructor-opt.js new file mode 100644 index 0000000..d0658fc --- /dev/null +++ b/src/v8/test/debugger/debug/es6/debug-promises/reject-in-constructor-opt.js
@@ -0,0 +1,64 @@ +// Copyright 2018 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. + + +// Test exercises code paths for catching exceptions in the promise constructor +// in conjunction with deoptimization. + +Debug = debug.Debug; + +var expected_events = 4; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Exception) { + expected_events--; + assertTrue(expected_events >= 0); + assertEquals("uncaught", event_data.exception().message); + assertTrue(event_data.uncaught()); + // The frame comes from the Promise.reject call + assertNotNull(/\/\/ EXCEPTION/.exec(event_data.sourceLineText())); + assertTrue(event_data.uncaught()); + } + } catch (e) { + %AbortJS(e + "\n" + e.stack); + } +} + +Debug.setBreakOnException(); +Debug.setListener(listener); + +function foo(a,b) { + let P = new Promise((resolve, reject) => { bar(a,b); resolve()}) + return P; +} + +function bar(a,b) { + %DeoptimizeFunction(foo); + throw new Error("uncaught"); // EXCEPTION +} + +%PrepareFunctionForOptimization(foo); + +foo(); +%PerformMicrotaskCheckpoint(); + +foo(); +%PerformMicrotaskCheckpoint(); + +%OptimizeFunctionOnNextCall(foo); + +// bar likely gets inlined into foo. +foo(); +%PerformMicrotaskCheckpoint(); + +%NeverOptimizeFunction(bar); +%PrepareFunctionForOptimization(foo); +%OptimizeFunctionOnNextCall(foo); + +// bar does not get inlined into foo. +foo(); +%PerformMicrotaskCheckpoint(); + +assertEquals(0, expected_events);
diff --git a/src/v8/test/debugger/debug/es6/debug-promises/throw-with-throw-in-reject.js b/src/v8/test/debugger/debug/es6/debug-promises/throw-with-throw-in-reject.js index b17054b..5cca2f9 100644 --- a/src/v8/test/debugger/debug/es6/debug-promises/throw-with-throw-in-reject.js +++ b/src/v8/test/debugger/debug/es6/debug-promises/throw-with-throw-in-reject.js
@@ -3,15 +3,13 @@ // found in the LICENSE file. -// Test debug events when an exception is thrown inside a Promise, which is -// caught by a custom promise, which throws a new exception in its reject -// handler. We expect two Exception debug events: -// 1) when the exception is thrown in the promise q. -// 2) when the custom reject closure in MyPromise throws an exception. +// Test debug events when an exception is thrown inside a Promise, +// which is caught by a custom promise, which throws a new exception +// in its reject handler. We expect no Exception debug events. Debug = debug.Debug; -var expected_events = 1; +var expected_events = 0; var log = []; var p = new Promise(function(resolve, reject) { @@ -21,11 +19,9 @@ function MyPromise(resolver) { var reject = function() { - log.push("throw in reject"); throw new Error("reject"); // event }; var resolve = function() { }; - log.push("construct"); resolver(resolve, reject); }; @@ -42,16 +38,7 @@ function listener(event, exec_state, event_data, data) { try { if (event == Debug.DebugEvent.Exception) { - expected_events--; - assertTrue(expected_events >= 0); - if (expected_events == 0) { - assertEquals(["resolve", "construct", "end main", - "throw caught"], log); - assertEquals("caught", event_data.exception().message); - } else { - assertUnreachable(); - } - assertTrue(exec_state.frame(0).sourceLineText().indexOf('// event') > 0); + assertUnreachable(); } } catch (e) { %AbortJS(e + "\n" + e.stack); @@ -68,8 +55,8 @@ try { assertTrue(iteration < 10); if (expected_events === 0) { - assertEquals(["resolve", "construct", "end main", - "throw caught", "throw in reject"], log); + assertEquals(["resolve", "end main", + "throw caught"], log); } else { testDone(iteration + 1); }
diff --git a/src/v8/test/debugger/debug/es6/debug-step-destructuring-bind.js b/src/v8/test/debugger/debug/es6/debug-step-destructuring-bind.js index 2e707b9..1ada64d 100644 --- a/src/v8/test/debugger/debug/es6/debug-step-destructuring-bind.js +++ b/src/v8/test/debugger/debug/es6/debug-step-destructuring-bind.js
@@ -21,7 +21,7 @@ } catch (e) { exception = e; print(e); - } + } // B34 }; Debug.setListener(listener); @@ -41,7 +41,7 @@ function f2([ a, // B7 b = id(3) // B8 - ]) { + ]) { assertEquals([4, 3], [a, b]); // B11 } // B12 f2([4]); // B6 @@ -49,7 +49,7 @@ function f3({ x: a, // B14 y: b // B15 - }) { + }) { assertEquals([5, 6], [a, b]); // B16 } // B17 f3({y: 6, x: 5}); // B13 @@ -60,7 +60,7 @@ b, // B20 c, // B21 } - ]) { + ]) { // B19 assertEquals([2, 4, 6], [a, b, c]); // B22 } // B23 f4([2, {c: 6, b: 4}]); // B18 @@ -98,12 +98,12 @@ } var { - x: a, - y: b = 9 + x: a, // B47 + y: b = 9 // B48 } = { x: 4 }; // B46 - assertEquals([4, 9], [a, b]); // B47 -} // B48 + assertEquals([4, 9], [a, b]); // B49 +} // B50 test(); -Debug.setListener(null); // B49 +Debug.setListener(null); // B51 assertNull(exception);
diff --git a/src/v8/test/debugger/debug/es6/generators-debug-liveedit.js b/src/v8/test/debugger/debug/es6/generators-debug-liveedit.js index 3ae359a..2627c8d 100644 --- a/src/v8/test/debugger/debug/es6/generators-debug-liveedit.js +++ b/src/v8/test/debugger/debug/es6/generators-debug-liveedit.js
@@ -2,9 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. - +// Flags: --allow-natives-syntax var Debug = debug.Debug; -var LiveEdit = Debug.LiveEdit; unique_id = 0; @@ -62,15 +61,7 @@ function patch(fun, from, to) { function debug() { - var log = new Array(); - var script = Debug.findScript(fun); - var pos = script.source.indexOf(from); - try { - LiveEdit.TestApi.ApplySingleChunkPatch(script, pos, from.length, to, - log); - } finally { - print("Change log: " + JSON.stringify(log) + "\n"); - } + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(from, to)); } ExecuteInDebugContext(debug); } @@ -84,8 +75,9 @@ function attempt_gen_patch() { assertFalse(gen_patch_attempted); gen_patch_attempted = true; - assertThrows(function() { patch(generator, "'Cat'", "'Capybara'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(generator, '\'Cat\'', '\'Capybara\'') + }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME'); }; var iter = generator(attempt_gen_patch); assertIteratorResult(undefined, false, iter.next()); @@ -104,8 +96,9 @@ // Patching will fail however when a live iterator is suspended. iter = generator(function(){}); assertIteratorResult(undefined, false, iter.next()); - assertThrows(function() { patch(generator, "'Capybara'", "'Tapir'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(generator, '\'Capybara\'', '\'Tapir\'') + }, 'LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR'); assertIteratorResult("Capybara", true, iter.next()); // Try to patch functions with activations inside and outside generator @@ -123,8 +116,9 @@ } fun_patch_attempted = true; // Patching outside a generator activation must fail. - assertThrows(function() { patch(fun_outside, "'Cat'", "'Cobra'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(fun_outside, '\'Cat\'', '\'Cobra\'') + }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME'); // Patching inside a generator activation may succeed. patch(fun_inside, "'Cat'", "'Koala'"); }
diff --git a/src/v8/test/debugger/debug/es6/generators-debug-scopes.js b/src/v8/test/debugger/debug/es6/generators-debug-scopes.js index a46dc8b..14752af 100644 --- a/src/v8/test/debugger/debug/es6/generators-debug-scopes.js +++ b/src/v8/test/debugger/debug/es6/generators-debug-scopes.js
@@ -42,8 +42,7 @@ run(function () { return fun.apply(null, args) }); run(function () { return gen.apply(null, args).next().value }); - // TODO(wingo): Uncomment after bug 2838 is fixed. - // Debug.setListener(null); + Debug.setListener(null); } // Check that two scope are the same.
diff --git a/src/v8/test/debugger/debug/es8/async-debug-basic.js b/src/v8/test/debugger/debug/es8/async-debug-basic.js index 9423fe5..ea87c67 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-basic.js +++ b/src/v8/test/debugger/debug/es8/async-debug-basic.js
@@ -4,8 +4,9 @@ Debug = debug.Debug -listenerComplete = false; -breakPointCount = 0; +let listenerComplete = false; +let breakPointCount = 0; +let exceptionThrown = false; async function f() { await (async function() { var a = "a"; await 1; debugger; })(); @@ -13,7 +14,7 @@ var b = "b"; assertTrue(listenerDone); - assertFalse(exception); + assertFalse(exceptionThrown); assertEquals(1, breakpointCount); } @@ -27,7 +28,7 @@ assertEquals("b", exec_state.frame(1).evaluate("b")); assertEquals("c", exec_state.frame(2).evaluate("c")); } catch (e) { - exception = e; + exceptionThrown = true; }; };
diff --git a/src/v8/test/debugger/debug/es8/async-debug-builtin-predictions.js b/src/v8/test/debugger/debug/es8/async-debug-builtin-predictions.js index 70f1b57..bcd9908 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-builtin-predictions.js +++ b/src/v8/test/debugger/debug/es8/async-debug-builtin-predictions.js
@@ -57,7 +57,7 @@ foo(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnException();
diff --git a/src/v8/test/debugger/debug/es8/async-debug-caught-exception-cases.js b/src/v8/test/debugger/debug/es8/async-debug-caught-exception-cases.js index f5c1ed9..24cf598 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-caught-exception-cases.js +++ b/src/v8/test/debugger/debug/es8/async-debug-caught-exception-cases.js
@@ -197,7 +197,7 @@ events = 0; consumer(producer); - %RunMicrotasks(); + %PerformMicrotaskCheckpoint(); Debug.setListener(null); if (caught) {
diff --git a/src/v8/test/debugger/debug/es8/async-debug-caught-exception.js b/src/v8/test/debugger/debug/es8/async-debug-caught-exception.js index 2feecc0..de0c4e9 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-caught-exception.js +++ b/src/v8/test/debugger/debug/es8/async-debug-caught-exception.js
@@ -37,7 +37,7 @@ Debug.setListener(listener); Debug.setBreakOnException(); caught_throw(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnException(); assertEquals(["a"], log); @@ -48,7 +48,7 @@ Debug.setListener(listener); Debug.setBreakOnUncaughtException(); caught_throw(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnUncaughtException(); assertEquals([], log); @@ -69,7 +69,7 @@ Debug.setListener(listener); Debug.setBreakOnException(); caught_reject(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnException(); assertEquals([], log); @@ -80,7 +80,7 @@ Debug.setListener(listener); Debug.setBreakOnUncaughtException(); caught_reject(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnUncaughtException(); assertEquals([], log); @@ -95,7 +95,7 @@ async function propagate_outer() { return propagate_inner(); } propagate_outer(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(["a"], log); assertNull(exception); @@ -104,7 +104,7 @@ async function propagate_await() { await 1; return thrower(); } async function propagate_await_outer() { return propagate_await(); } propagate_await_outer(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(["a"], log); assertNull(exception); @@ -113,7 +113,7 @@ log = []; Promise.resolve().then(() => Promise.reject()).catch(() => log.push("d")); // Exception c -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(["d"], log); assertNull(exception);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-abort-at-break.js b/src/v8/test/debugger/debug/es8/async-debug-step-abort-at-break.js index 85232b0..47605ce 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-abort-at-break.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-abort-at-break.js
@@ -48,6 +48,6 @@ late_resolve(3); // B4 Continue -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(5, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-continue-at-break.js b/src/v8/test/debugger/debug/es8/async-debug-step-continue-at-break.js index a4726bd..79dcad6 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-continue-at-break.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-continue-at-break.js
@@ -37,8 +37,8 @@ a += await // B1 StepIn g(); // B2 StepIn - return a; // B4 StepNext -} // B5 Continue + return a; // B4 Continue +} f(); @@ -48,6 +48,6 @@ late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(6, step_count); +assertEquals(5, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-in-and-out.js b/src/v8/test/debugger/debug/es8/async-debug-step-in-and-out.js index 43fb16f..5d64e5a 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-in-and-out.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-in-and-out.js
@@ -37,13 +37,13 @@ a += await // B1 StepIn g(); - return a; // B3 StepNext -} // B4 Continue + return a; // B3 Continue +} f(); late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(5, step_count); +assertEquals(4, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-in-out-out.js b/src/v8/test/debugger/debug/es8/async-debug-step-in-out-out.js index c1d8fd7..7702742 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-in-out-out.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-in-out-out.js
@@ -44,6 +44,6 @@ late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(4, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-in.js b/src/v8/test/debugger/debug/es8/async-debug-step-in.js index c32fa2f..fe84e4b 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-in.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-in.js
@@ -37,13 +37,13 @@ a += await // B1 StepIn g(); - return a; // B6 StepIn -} // B7 Continue + return a; // B6 Continue +} f().then(value => assertEquals(4, value)); late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(8, step_count); +assertEquals(7, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-nested.js b/src/v8/test/debugger/debug/es8/async-debug-step-nested.js index 79e8dfaa..74432a6 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-nested.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-nested.js
@@ -37,8 +37,8 @@ a += await // B1 StepIn f2(); // B2 StepIn - return a; // B5 StepNext -} // B6 Continue + return a; // B5 Continue +} async function f2() { var b = 0 + // B2 StepIn @@ -51,6 +51,6 @@ late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(7, step_count); +assertEquals(6, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-next-constant.js b/src/v8/test/debugger/debug/es8/async-debug-step-next-constant.js index 32833ac..2b43263 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-next-constant.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-next-constant.js
@@ -27,11 +27,11 @@ a += // B1 StepNext await 5; - return a; // B2 StepNext -} // B3 Continue + return a; // B2 Continue +} f(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(4, step_count); +assertEquals(3, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-next.js b/src/v8/test/debugger/debug/es8/async-debug-step-next.js index 597afd3..0fdbd73 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-next.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-next.js
@@ -37,13 +37,13 @@ a += await // B1 StepNext g(); - return a; // B2 StepNext -} // B3 Continue + return a; // B2 Continue +} f(); late_resolve(3); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); -assertEquals(4, step_count); +assertEquals(3, step_count);
diff --git a/src/v8/test/debugger/debug/es8/async-debug-step-out.js b/src/v8/test/debugger/debug/es8/async-debug-step-out.js index 3ec6dd3..d37ce58 100644 --- a/src/v8/test/debugger/debug/es8/async-debug-step-out.js +++ b/src/v8/test/debugger/debug/es8/async-debug-step-out.js
@@ -42,6 +42,6 @@ late_resolve(3); // B2 Continue -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEquals(3, step_count);
diff --git a/src/v8/test/debugger/debug/es8/debug-async-break-on-stack.js b/src/v8/test/debugger/debug/es8/debug-async-break-on-stack.js index df389f3..124cbab 100644 --- a/src/v8/test/debugger/debug/es8/debug-async-break-on-stack.js +++ b/src/v8/test/debugger/debug/es8/debug-async-break-on-stack.js
@@ -21,7 +21,7 @@ assertFalse(hadValue || hadError); - %RunMicrotasks(); + %PerformMicrotaskCheckpoint(); if (hadError) throw actual; @@ -67,7 +67,7 @@ f(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEqualsAsync(2, async () => break_count); assertEqualsAsync(null, async () => exception);
diff --git a/src/v8/test/debugger/debug/es8/debug-async-break.js b/src/v8/test/debugger/debug/es8/debug-async-break.js index 3e07ba9..8a29820 100644 --- a/src/v8/test/debugger/debug/es8/debug-async-break.js +++ b/src/v8/test/debugger/debug/es8/debug-async-break.js
@@ -21,7 +21,7 @@ assertFalse(hadValue || hadError); - %RunMicrotasks(); + %PerformMicrotaskCheckpoint(); if (hadError) throw actual; @@ -65,7 +65,7 @@ f(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); assertEqualsAsync(3, async () => break_count); assertEqualsAsync(null, async () => exception);
diff --git a/src/v8/test/debugger/debug/es8/debug-async-liveedit.js b/src/v8/test/debugger/debug/es8/debug-async-liveedit.js index 761a24f..e85cbe3 100644 --- a/src/v8/test/debugger/debug/es8/debug-async-liveedit.js +++ b/src/v8/test/debugger/debug/es8/debug-async-liveedit.js
@@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// Flags: --allow-natives-syntax + var Debug = debug.Debug; -var LiveEdit = Debug.LiveEdit; unique_id = 0; @@ -69,16 +70,7 @@ function patch(fun, from, to) { function debug() { - var log = new Array(); - var script = Debug.findScript(fun); - var pos = script.source.indexOf(from); - print(`pos ${pos}`); - try { - LiveEdit.TestApi.ApplySingleChunkPatch(script, pos, from.length, to, - log); - } finally { - print("Change log: " + JSON.stringify(log) + "\n"); - } + %LiveEditPatchScript(fun, Debug.scriptSource(fun).replace(from, to)); } ExecuteInDebugContext(debug); } @@ -92,8 +84,9 @@ function attempt_patch() { assertFalse(patch_attempted); patch_attempted = true; - assertThrows(function() { patch(asyncfn, "'Cat'", "'Capybara'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(asyncfn, '\'Cat\'', '\'Capybara\'') + }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME'); }; var promise = asyncfn(attempt_patch); // Patch should not succeed because there is a live async function activation @@ -101,7 +94,7 @@ assertPromiseValue("Cat", promise); assertTrue(patch_attempted); - %RunMicrotasks(); + %PerformMicrotaskCheckpoint(); // At this point one iterator is live, but closed, so the patch will succeed. patch(asyncfn, "'Cat'", "'Capybara'"); @@ -112,15 +105,16 @@ // Patching will fail however when an async function is suspended. var resolve; promise = asyncfn(function(){return new Promise(function(r){resolve = r})}); - assertThrows(function() { patch(asyncfn, "'Capybara'", "'Tapir'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(asyncfn, '\'Capybara\'', '\'Tapir\'') + }, 'LiveEdit failed: BLOCKED_BY_RUNNING_GENERATOR'); resolve(); assertPromiseValue("Capybara", promise); // Try to patch functions with activations inside and outside async // function activations. We should succeed in the former case, but not in the // latter. - var fun_outside = MakeFunction(); + var fun_outside = eval('((callback) => { callback(); return \'Cat\';})'); var fun_inside = MakeFunction(); var fun_patch_attempted = false; var fun_patch_restarted = false; @@ -132,18 +126,21 @@ } fun_patch_attempted = true; // Patching outside an async function activation must fail. - assertThrows(function() { patch(fun_outside, "'Cat'", "'Cobra'") }, - LiveEdit.Failure); + assertThrowsEquals(function() { + patch(fun_outside, '\'Cat\'', '\'Cobra\'') + }, 'LiveEdit failed: BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME'); // Patching inside an async function activation may succeed. patch(fun_inside, "'Cat'", "'Koala'"); } - promise = asyncfn(function() { return fun_inside(attempt_fun_patches) }); + result = fun_outside(() => asyncfn(function() { + return fun_inside(attempt_fun_patches); + })); assertEquals('Cat', fun_outside(function () { - assertPromiseValue('Capybara', promise); + assertEquals(result, 'Cat'); assertTrue(fun_patch_restarted); assertTrue(fun_inside.toString().includes("'Koala'")); })); })(); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint();
diff --git a/src/v8/test/debugger/debug/es8/promise-finally.js b/src/v8/test/debugger/debug/es8/promise-finally.js index 2598ae0..dc7833e 100644 --- a/src/v8/test/debugger/debug/es8/promise-finally.js +++ b/src/v8/test/debugger/debug/es8/promise-finally.js
@@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Flags: --harmony-promise-finally - Debug = debug.Debug var exception = null; @@ -37,7 +35,7 @@ .finally(() => thenable) .catch(e => caughtException = e); -%RunMicrotasks(); +%PerformMicrotaskCheckpoint(); Debug.setListener(null); Debug.clearBreakOnException();
diff --git a/src/v8/test/debugger/debug/for-in-opt.js b/src/v8/test/debugger/debug/for-in-opt.js index 405199d..2b97e49 100644 --- a/src/v8/test/debugger/debug/for-in-opt.js +++ b/src/v8/test/debugger/debug/for-in-opt.js
@@ -14,6 +14,8 @@ return result; } +%PrepareFunctionForOptimization(f); + assertEquals(["0"], f("a")); assertEquals(["0"], f("a")); @@ -62,6 +64,8 @@ property_descriptor_keys.length = 0; } +%PrepareFunctionForOptimization(f2); + check_f2(); check_f2(); @@ -71,6 +75,7 @@ check_f2(); // Test lazy deopt after FILTER_KEY +%PrepareFunctionForOptimization(f2); %OptimizeFunctionOnNextCall(f2); deopt_property_descriptor = true; check_f2(); @@ -81,6 +86,7 @@ } } +%PrepareFunctionForOptimization(f3); f3({__proto__:{x:1}}); f3({__proto__:{x:1}}); @@ -106,6 +112,8 @@ property_descriptor_keys.length = 0; } +%PrepareFunctionForOptimization(f4); + check_f4(); check_f4(); @@ -146,6 +154,7 @@ x = false; +%PrepareFunctionForOptimization(f5); f5(); f5(); f5(); %OptimizeFunctionOnNextCall(f5); x = true;
diff --git a/src/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs b/src/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs new file mode 100644 index 0000000..1789798 --- /dev/null +++ b/src/v8/test/debugger/debug/harmony/modules-debug-scopes1.mjs
@@ -0,0 +1,870 @@ +// Copyright 2016 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. +// Flags: --allow-natives-syntax --noanalyze-environment-liveness + +// These tests are copied from mjsunit/debug-scopes.js and adapted for modules. + + +var Debug = debug.Debug; + +var test_name; +var listener_delegate; +var listener_called; +var exception; +var begin_test_count = 0; +var end_test_count = 0; +var break_count = 0; + + +// Debug event listener which delegates. +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + break_count++; + listener_called = true; + listener_delegate(exec_state); + } + } catch (e) { + exception = e; + } +} + +// Add the debug event listener. +Debug.setListener(listener); + + +// Initialize for a new test. +function BeginTest(name) { + test_name = name; + listener_delegate = null; + listener_called = false; + exception = null; + begin_test_count++; +} + + +// Check result of a test. +function EndTest() { + assertTrue(listener_called, "listener not called for " + test_name); + assertNull(exception, test_name + " / " + exception); + end_test_count++; +} + + +// Check that two scope are the same. +function assertScopeMirrorEquals(scope1, scope2) { + assertEquals(scope1.scopeType(), scope2.scopeType()); + assertEquals(scope1.frameIndex(), scope2.frameIndex()); + assertEquals(scope1.scopeIndex(), scope2.scopeIndex()); + assertPropertiesEqual(scope1.scopeObject().value(), + scope2.scopeObject().value()); +} + +function CheckFastAllScopes(scopes, exec_state) +{ + var fast_all_scopes = exec_state.frame().allScopes(true); + var length = fast_all_scopes.length; + assertTrue(scopes.length >= length); + for (var i = 0; i < scopes.length && i < length; i++) { + var scope = fast_all_scopes[length - i - 1]; + assertEquals(scopes[scopes.length - i - 1], scope.scopeType()); + } +} + + +// Check that the scope chain contains the expected types of scopes. +function CheckScopeChain(scopes, exec_state) { + var all_scopes = exec_state.frame().allScopes(); + assertEquals(scopes.length, exec_state.frame().scopeCount()); + assertEquals(scopes.length, all_scopes.length, + "FrameMirror.allScopes length"); + for (var i = 0; i < scopes.length; i++) { + var scope = exec_state.frame().scope(i); + assertEquals(scopes[i], scope.scopeType()); + assertScopeMirrorEquals(all_scopes[i], scope); + } + CheckFastAllScopes(scopes, exec_state); +} + + +// Check that the scope chain contains the expected names of scopes. +function CheckScopeChainNames(names, exec_state) { + var all_scopes = exec_state.frame().allScopes(); + assertEquals(names.length, all_scopes.length, "FrameMirror.allScopes length"); + for (var i = 0; i < names.length; i++) { + var scope = exec_state.frame().scope(i); + // assertEquals(names[i], scope.details().name()) + } +} + + +// Check that the scope contains at least minimum_content. For functions just +// check that there is a function. +function CheckScopeContent(minimum_content, number, exec_state) { + var scope = exec_state.frame().scope(number); + var minimum_count = 0; + for (var p in minimum_content) { + var property_mirror = scope.scopeObject().property(p); + assertFalse(property_mirror.isUndefined(), + 'property ' + p + ' not found in scope'); + assertEquals(minimum_content[p], property_mirror.value().value(), + 'property ' + p + ' has unexpected value'); + minimum_count++; + } + + // 'arguments' and might be exposed in the local and closure scope. Just + // ignore this. + var scope_size = scope.scopeObject().properties().length; + if (!scope.scopeObject().property('arguments').isUndefined()) { + scope_size--; + } + // Ditto for 'this'. + if (!scope.scopeObject().property('this').isUndefined()) { + scope_size--; + } + // Temporary variables introduced by the parser have not been materialized. + assertTrue(scope.scopeObject().property('').isUndefined()); + + if (scope_size < minimum_count) { + print('Names found in scope:'); + var names = scope.scopeObject().propertyNames(); + for (var i = 0; i < names.length; i++) { + print(names[i]); + } + } + assertTrue(scope_size >= minimum_count); +} + +// Check that the scopes have positions as expected. +function CheckScopeChainPositions(positions, exec_state) { + var all_scopes = exec_state.frame().allScopes(); + assertTrue(positions.length <= all_scopes.length, + "FrameMirror.allScopes length"); + for (var i = 0; i < positions.length; i++) { + var scope = exec_state.frame().scope(i); + var position = positions[i]; + if (!position) + continue; + + print( + `Checking position.start = ${position.start}, .end = ${position.end}`); + // assertEquals(position.start, scope.details().startPosition()) + // assertEquals(position.end, scope.details().endPosition()) + } +} + +// Simple empty local scope. +BeginTest("Local 1"); + +function local_1() { + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({}, 0, exec_state); +}; +local_1(); +EndTest(); + + +// Local scope with a parameter. +BeginTest("Local 2"); + +function local_2(a) { + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1}, 0, exec_state); +}; +local_2(1); +EndTest(); + + +// Local scope with a parameter and a local variable. +BeginTest("Local 3"); + +function local_3(a) { + var x = 3; + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,x:3}, 0, exec_state); +}; +local_3(1); +EndTest(); + + +// Local scope with parameters and local variables. +BeginTest("Local 4"); + +function local_4(a, b) { + var x = 3; + var y = 4; + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state); +}; +local_4(1, 2); +EndTest(); + + +// Empty local scope with use of eval. +BeginTest("Local 5"); + +function local_5() { + eval(''); + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({}, 0, exec_state); +}; +local_5(); +EndTest(); + + +// Local introducing local variable using eval. +BeginTest("Local 6"); + +function local_6() { + eval('var i = 5'); + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({}, 0, exec_state); +}; +local_6(); +EndTest(); + + +// Local scope with parameters and local variables. +BeginTest("Local 7"); + +function local_7(a, b) { + var x = 3; + var y = 4; + eval('var i = 5'); + eval('var j = 6'); + debugger; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4}, 0, exec_state); +}; +local_7(1, 2); +EndTest(); + + +// Simple closure formed by returning an inner function referering the outer +// functions arguments. +BeginTest("Closure 1"); + +function closure_1(a) { + function f() { + debugger; + return a; + }; + return f; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1}, 1, exec_state); + CheckScopeChainNames(["f", "closure_1", undefined, undefined, undefined], exec_state) +}; +closure_1(1)(); +EndTest(); + + +// Simple closure formed by returning an inner function referering the outer +// functions arguments. Due to VM optimizations parts of the actual closure is +// missing from the debugger information. +BeginTest("Closure 2"); + +function closure_2(a, b) { + var x = a + 2; + var y = b + 2; + function f() { + debugger; + return a + x; + }; + return f; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,x:3}, 1, exec_state); + CheckScopeChainNames(["f", "closure_2", undefined, undefined, undefined], + exec_state) +}; +closure_2(1, 2)(); +EndTest(); + + +// Simple closure formed by returning an inner function referering the outer +// functions arguments. Using all arguments and locals from the outer function +// in the inner function makes these part of the debugger information on the +// closure. +BeginTest("Closure 3"); + +function closure_3(a, b) { + var x = a + 2; + var y = b + 2; + function f() { + debugger; + return a + b + x + y; + }; + return f; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state); + CheckScopeChainNames(["f", "closure_3", undefined, undefined, undefined], + exec_state) +}; +closure_3(1, 2)(); +EndTest(); + + + +// Simple closure formed by returning an inner function referering the outer +// functions arguments. Using all arguments and locals from the outer function +// in the inner function makes these part of the debugger information on the +// closure. Use the inner function as well... +BeginTest("Closure 4"); + +function closure_4(a, b) { + var x = a + 2; + var y = b + 2; + function f() { + debugger; + if (f) { + return a + b + x + y; + } + }; + return f; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4,f:undefined}, 1, exec_state); + CheckScopeChainNames(["f", "closure_4", undefined, undefined, undefined], + exec_state) +}; +closure_4(1, 2)(); +EndTest(); + + + +// Simple closure formed by returning an inner function referering the outer +// functions arguments. In the presence of eval all arguments and locals +// (including the inner function itself) from the outer function becomes part of +// the debugger infformation on the closure. +BeginTest("Closure 5"); + +function closure_5(a, b) { + var x = 3; + var y = 4; + function f() { + eval(''); + debugger; + return 1; + }; + return f; +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4,f:undefined}, 1, exec_state); + CheckScopeChainNames(["f", "closure_5", undefined, undefined, undefined], + exec_state) +}; +closure_5(1, 2)(); +EndTest(); + + +// Two closures. Due to optimizations only the parts actually used are provided +// through the debugger information. +BeginTest("Closure 6"); +let some_global; +function closure_6(a, b) { + function f(a, b) { + var x = 3; + var y = 4; + return function() { + var x = 3; + var y = 4; + debugger; + some_global = a; + return f; + }; + } + return f(a, b); +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({a:1}, 1, exec_state); + CheckScopeContent({f:undefined}, 2, exec_state); + CheckScopeChainNames( + [undefined, "f", "closure_6", undefined, undefined, undefined], + exec_state); +}; +closure_6(1, 2)(); +EndTest(); + + +// Two closures. In the presence of eval all information is provided as the +// compiler cannot determine which parts are used. +BeginTest("Closure 7"); +function closure_7(a, b) { + var x = 3; + var y = 4; + eval('var i = 5'); + eval('var j = 6'); + function f(a, b) { + var x = 3; + var y = 4; + eval('var i = 5'); + eval('var j = 6'); + return function() { + debugger; + some_global = a; + return f; + }; + } + return f(a, b); +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Closure, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({}, 0, exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4}, 1, exec_state); + CheckScopeContent({a:1,b:2,x:3,y:4,f:undefined}, 2, exec_state); + CheckScopeChainNames( + [undefined, "f", "closure_7", undefined, undefined, undefined], + exec_state); +}; +closure_7(1, 2)(); +EndTest(); + + +// Closure that may be optimized out. +BeginTest("Closure 8"); +function closure_8() { + (function inner(x) { + debugger; + })(2); +} + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x: 2}, 0, exec_state); + CheckScopeChainNames(["inner", undefined, undefined, undefined], exec_state); +}; +closure_8(); +EndTest(); + + +BeginTest("Closure 9"); +let closure_9 = Function(' \ + eval("var y = 1;"); \ + eval("var z = 1;"); \ + (function inner(x) { \ + y++; \ + z++; \ + debugger; \ + })(2); \ +') + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Closure, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainNames(["inner", undefined, undefined, undefined], exec_state); +}; +closure_9(); +EndTest(); + + +// Test global scope. +BeginTest("Global"); +listener_delegate = function(exec_state) { + CheckScopeChain( + [debug.ScopeType.Module, debug.ScopeType.Script, debug.ScopeType.Global], + exec_state); + CheckScopeChainNames([undefined, undefined, undefined], exec_state); +}; +debugger; +EndTest(); + + +BeginTest("Catch block 1"); +function catch_block_1() { + try { + throw 'Exception'; + } catch (e) { + debugger; + } +}; + + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Catch, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({e:'Exception'}, 0, exec_state); + CheckScopeChainNames( + ["catch_block_1", "catch_block_1", undefined, undefined, undefined], + exec_state); +}; +catch_block_1(); +EndTest(); + + +BeginTest("Catch block 3"); +function catch_block_3() { + eval("var y = 78;"); + try { + throw 'Exception'; + } catch (e) { + debugger; + } +}; + + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Catch, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({e:'Exception'}, 0, exec_state); + CheckScopeContent({}, 1, exec_state); + CheckScopeChainNames( + ["catch_block_3", "catch_block_3", undefined, undefined, undefined], + exec_state); +}; +catch_block_3(); +EndTest(); + + +// Test catch in global scope. +BeginTest("Catch block 5"); +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Catch, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({e:'Exception'}, 0, exec_state); + CheckScopeChainNames([undefined, undefined, undefined, undefined], + exec_state); +}; + +try { + throw 'Exception'; +} catch (e) { + debugger; +} + +EndTest(); + + +// Closure inside catch in global code. +BeginTest("Catch block 6"); +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Catch, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({x: 2}, 0, exec_state); + CheckScopeContent({e:'Exception'}, 1, exec_state); + CheckScopeChainNames([undefined, undefined, undefined, undefined, undefined], + exec_state); +}; + +try { + throw 'Exception'; +} catch (e) { + (function(x) { + debugger; + })(2); +} +EndTest(); + + +// Catch block in function that is marked for optimization while being executed. +BeginTest("Catch block 7"); +function catch_block_7() { + %OptimizeFunctionOnNextCall(catch_block_7); + try { + throw 'Exception'; + } catch (e) { + debugger; + } +}; + +%PrepareFunctionForOptimization(catch_block_7); + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Catch, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({e:'Exception'}, 0, exec_state); + CheckScopeChainNames( + ["catch_block_7", "catch_block_7", undefined, undefined, undefined], + exec_state); +}; +catch_block_7(); +EndTest(); + + +BeginTest("Classes and methods 1"); + +listener_delegate = function(exec_state) { + "use strict" + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent({}, 1, exec_state); + CheckScopeChainNames(["m", undefined, undefined, undefined], exec_state); +}; + +(function() { + "use strict"; + class C1 { + m() { + debugger; + } + } + new C1().m(); +})(); + +EndTest(); + +BeginTest("Scope positions"); +var code1 = "function f() { \n" + + " var a = 1; \n" + + " function b() { \n" + + " debugger; \n" + + " return a + 1; \n" + + " } \n" + + " b(); \n" + + "} \n" + + "f(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChainPositions([{start: 58, end: 118}, {start: 10, end: 162}], + exec_state); +} +eval(code1); +EndTest(); + + +BeginTest("Scope positions in for statement"); +var code3 = "function for_statement() { \n" + + " for (let i = 0; i < 1; i++) { \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 42, end: 111}, {start: 22, end: 145}], + exec_state); +} +eval(code3); +EndTest(); + +BeginTest("Scope positions in for statement with lexical block"); +var code4 = "function for_statement() { \n" + + " for (let i = 0; i < 1; i++) { \n" + + " let j; \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 66, end: 147}, + {start: 42, end: 147}, + {start: 22, end: 181}], exec_state); +} +eval(code4); +EndTest(); + +BeginTest("Scope positions in lexical for each statement"); +var code5 = "function for_each_statement() { \n" + + " for (let i of [0]) { \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_each_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 55, end: 111}, {start: 27, end: 145}], + exec_state); +} +eval(code5); +EndTest(); + +BeginTest("Scope positions in lexical for each statement with lexical block"); +var code6 = "function for_each_statement() { \n" + + " for (let i of [0]) { \n" + + " let j; \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_each_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 57, end: 147}, + {start: 55, end: 147}, + {start: 27, end: 181}], exec_state); +} +eval(code6); +EndTest(); + +BeginTest("Scope positions in non-lexical for each statement"); +var code7 = "function for_each_statement() { \n" + + " var i; \n" + + " for (i of [0]) { \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_each_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 27, end: 181}], exec_state); +} +eval(code7); +EndTest(); + +BeginTest( + "Scope positions in non-lexical for each statement with lexical block"); +var code8 = "function for_each_statement() { \n" + + " var i; \n" + + " for (i of [0]) { \n" + + " let j; \n" + + " debugger; \n" + + " } \n" + + "} \n" + + "for_each_statement(); \n"; + +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Block, + debug.ScopeType.Local, + debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeChainPositions([{start: 89, end: 183}, {start: 27, end: 217}], + exec_state); +} +eval(code8); +EndTest(); + +assertEquals(begin_test_count, break_count, + 'one or more tests did not enter the debugger'); +assertEquals(begin_test_count, end_test_count, + 'one or more tests did not have its result checked');
diff --git a/src/v8/test/debugger/debug/harmony/modules-debug-scopes2.mjs b/src/v8/test/debugger/debug/harmony/modules-debug-scopes2.mjs new file mode 100644 index 0000000..a23ee9f --- /dev/null +++ b/src/v8/test/debugger/debug/harmony/modules-debug-scopes2.mjs
@@ -0,0 +1,184 @@ +// Copyright 2016 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. + +var Debug = debug.Debug; + +var test_name; +var listener_delegate; +var listener_called; +var exception; +var begin_test_count = 0; +var end_test_count = 0; +var break_count = 0; + +function listener(event, exec_state, event_data, data) { + try { + if (event == Debug.DebugEvent.Break) { + break_count++; + listener_called = true; + listener_delegate(exec_state); + } + } catch (e) { + exception = e; + } +} + +Debug.setListener(listener); + + +function BeginTest(name) { + test_name = name; + listener_delegate = null; + listener_called = false; + exception = null; + begin_test_count++; +} + +function EndTest() { + assertTrue(listener_called, "listener not called for " + test_name); + assertNull(exception, test_name + " / " + exception); + end_test_count++; +} + + +// Check that two scope are the same. +function assertScopeMirrorEquals(scope1, scope2) { + assertEquals(scope1.scopeType(), scope2.scopeType()); + assertEquals(scope1.frameIndex(), scope2.frameIndex()); + assertEquals(scope1.scopeIndex(), scope2.scopeIndex()); + assertPropertiesEqual(scope1.scopeObject().value(), + scope2.scopeObject().value()); +} + +function CheckFastAllScopes(scopes, exec_state) +{ + var fast_all_scopes = exec_state.frame().allScopes(true); + var length = fast_all_scopes.length; + assertTrue(scopes.length >= length); + for (var i = 0; i < scopes.length && i < length; i++) { + var scope = fast_all_scopes[length - i - 1]; + assertEquals(scopes[scopes.length - i - 1], scope.scopeType()); + } +} + + +// Check that the scope chain contains the expected types of scopes. +function CheckScopeChain(scopes, exec_state) { + var all_scopes = exec_state.frame().allScopes(); + assertEquals(scopes.length, exec_state.frame().scopeCount()); + assertEquals(scopes.length, all_scopes.length, "FrameMirror.allScopes length"); + for (var i = 0; i < scopes.length; i++) { + var scope = exec_state.frame().scope(i); + assertEquals(scopes[i], scope.scopeType()); + assertScopeMirrorEquals(all_scopes[i], scope); + } + CheckFastAllScopes(scopes, exec_state); +} + + +function CheckScopeDoesNotHave(properties, number, exec_state) { + var scope = exec_state.frame().scope(number); + for (var p of properties) { + var property_mirror = scope.scopeObject().property(p); + assertTrue(property_mirror.isUndefined(), + 'property ' + p + ' found in scope'); + } +} + + +// Check that the scope contains at least minimum_content. For functions just +// check that there is a function. +function CheckScopeContent(minimum_content, number, exec_state) { + var scope = exec_state.frame().scope(number); + var minimum_count = 0; + for (var p in minimum_content) { + var property_mirror = scope.scopeObject().property(p); + assertFalse(property_mirror.isUndefined(), + 'property ' + p + ' not found in scope'); + assertEquals(minimum_content[p], property_mirror.value().value(), + 'property ' + p + ' has unexpected value'); + minimum_count++; + } + + // 'arguments' and might be exposed in the local and closure scope. Just + // ignore this. + var scope_size = scope.scopeObject().properties().length; + if (!scope.scopeObject().property('arguments').isUndefined()) { + scope_size--; + } + // Ditto for 'this'. + if (!scope.scopeObject().property('this').isUndefined()) { + scope_size--; + } + // Temporary variables introduced by the parser have not been materialized. + assertTrue(scope.scopeObject().property('').isUndefined()); + + if (scope_size < minimum_count) { + print('Names found in scope:'); + var names = scope.scopeObject().propertyNames(); + for (var i = 0; i < names.length; i++) { + print(names[i]); + } + } + assertTrue(scope_size >= minimum_count); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Actual tests. +//////////////////////////////////////////////////////////////////////////////// + + +BeginTest(); +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent( + {exported_var: undefined, imported_var: undefined}, + 0, exec_state); + CheckScopeDoesNotHave( + ["doesntexist", "exported_let", "imported_let"], + 0, exec_state); +}; +debugger; +EndTest(); + +let local_let = 1; +var local_var = 2; +export let exported_let = 3; +export var exported_var = 4; +import {exported_let as imported_let} from "modules-debug-scopes2.mjs"; +import {exported_var as imported_var} from "modules-debug-scopes2.mjs"; + +BeginTest(); +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent( + {exported_let: 3, exported_var: 4, + imported_let: 3, imported_var: 4}, 0, exec_state); + CheckScopeDoesNotHave([], 0, exec_state); +}; +debugger; +EndTest(); + +local_let += 10; +local_var += 10; +exported_let += 10; +exported_var += 10; + +BeginTest(); +listener_delegate = function(exec_state) { + CheckScopeChain([debug.ScopeType.Module, + debug.ScopeType.Script, + debug.ScopeType.Global], exec_state); + CheckScopeContent( + {exported_let: 13, exported_var: 14, + imported_let: 13, imported_var: 14}, 0, exec_state); + CheckScopeDoesNotHave([], 0, exec_state); +}; +debugger; +EndTest();
diff --git a/src/v8/test/debugger/debug/ignition/optimized-debug-frame.js b/src/v8/test/debugger/debug/ignition/optimized-debug-frame.js index cc85b47..a317350 100644 --- a/src/v8/test/debugger/debug/ignition/optimized-debug-frame.js +++ b/src/v8/test/debugger/debug/ignition/optimized-debug-frame.js
@@ -23,6 +23,7 @@ break_count++; } +%PrepareFunctionForOptimization(g); g(); g(); %OptimizeFunctionOnNextCall(g);
diff --git a/src/v8/test/debugger/debug/lazy-deopt-then-flush-bytecode.js b/src/v8/test/debugger/debug/lazy-deopt-then-flush-bytecode.js new file mode 100644 index 0000000..6820dc0 --- /dev/null +++ b/src/v8/test/debugger/debug/lazy-deopt-then-flush-bytecode.js
@@ -0,0 +1,49 @@ +// Copyright 2018 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. + +// Flags: --allow-natives-syntax --opt --noalways-opt --stress-flush-bytecode +// Flags: --expose-gc + +Debug = debug.Debug + +function foo() { + return 44; +} + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + + // Optimize foo. + %PrepareFunctionForOptimization(foo); + %OptimizeFunctionOnNextCall(foo); + foo(); + assertOptimized(foo); + + // Lazily deopt foo, which marks the code for deoptimization and invalidates + // the DeoptimizationData, but doesn't unlink the optimized code entry in + // foo's JSFunction. + %DeoptimizeFunction(foo); + + // Run the GC. Since the DeoptimizationData is now dead, the bytecode + // associated with the optimized code is free to be flushed, which also + // free's the feedback vector meta-data. + gc(); + + // Execute foo with side-effect checks, which causes the debugger to call + // DeoptimizeFunction on foo. Even though the code is already marked for + // deoptimization, this will try to unlink the optimized code from the + // feedback vector, which will fail due to the feedback meta-data being + // flushed. The deoptimizer should call JSFunction::ResetIfBytecodeFlushed + // before trying to do this, which will clear the whole feedback vector and + // reset the JSFunction's code entry field to CompileLazy. + exec_state.frame(0).evaluate("foo()", true); +} + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +} +f();
diff --git a/src/v8/test/debugger/debug/regress-3225.js b/src/v8/test/debugger/debug/regress-3225.js index 454ff6e..4ba6777 100644 --- a/src/v8/test/debugger/debug/regress-3225.js +++ b/src/v8/test/debugger/debug/regress-3225.js
@@ -32,6 +32,8 @@ function* generator(a, b) { function set_a_to_5() { a = 5 } + // Make sure set_a_to_5 is 'used' so that it is visible to the debugger. + set_a_to_5; var b = 3; // Shadows a parameter. debugger; yield a;
diff --git a/src/v8/test/debugger/debug/regress/regress-1081309.js b/src/v8/test/debugger/debug/regress/regress-1081309.js index 5e4cd88..0b32fa5 100644 --- a/src/v8/test/debugger/debug/regress/regress-1081309.js +++ b/src/v8/test/debugger/debug/regress/regress-1081309.js
@@ -29,8 +29,8 @@ // Make sure that the backtrace command can be processed when the receiver is // undefined. -listenerCalled = false; -exception = false; +let listenerCalled = false; +let exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -47,7 +47,7 @@ } } catch (e) { print(e); - exception = e + exceptionThrown = true; }; }; @@ -67,6 +67,6 @@ // Ignore the exception "Cannot call method 'x' of undefined" } -assertFalse(exception, "exception in listener", exception) +assertFalse(exceptionThrown, "exception in listener"); // Make sure that the debug event listener vas invoked. assertTrue(listenerCalled, "listener not called");
diff --git a/src/v8/test/debugger/debug/regress/regress-1170187.js b/src/v8/test/debugger/debug/regress/regress-1170187.js index 165a308..e41cc7e 100644 --- a/src/v8/test/debugger/debug/regress/regress-1170187.js +++ b/src/v8/test/debugger/debug/regress/regress-1170187.js
@@ -31,8 +31,8 @@ Debug = debug.Debug -listenerCalled = false; -exception = false; +let listenerCalled = false; +let exceptionThrown = false; function checkName(name) { @@ -64,7 +64,7 @@ listenerCalled = true; } } catch (e) { - exception = e; + exceptionThrown = true; }; }; @@ -73,8 +73,14 @@ // Call a function with local variables passing a different number parameters // that the number of arguments. -(function(x,y){var a,b,c; debugger; return 3})() +(function(x,y){ + var a,b,c; + // Make sure a, b, and c are used. + a,b,c; + debugger; + return 3 +})() // Make sure that the debug event listener vas invoked (again). assertTrue(listenerCalled); -assertFalse(exception, "exception in listener") +assertFalse(exceptionThrown, "exception in listener")
diff --git a/src/v8/test/debugger/debug/regress/regress-119609.js b/src/v8/test/debugger/debug/regress/regress-119609.js index b6da891..a1ad32a 100644 --- a/src/v8/test/debugger/debug/regress/regress-119609.js +++ b/src/v8/test/debugger/debug/regress/regress-119609.js
@@ -28,7 +28,7 @@ Debug = debug.Debug; -var exception = false; +var exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -44,7 +44,7 @@ assertThrows(() => lookup("b"), ReferenceError); } } catch (e) { - exception = e.toString() + e.stack; + exceptionThrown = true; } } @@ -63,4 +63,4 @@ f(1, 2)(3, 4); -assertFalse(exception); +assertFalse(exceptionThrown);
diff --git a/src/v8/test/debugger/debug/regress/regress-131994.js b/src/v8/test/debugger/debug/regress/regress-131994.js index 66bde74..ee431d0 100644 --- a/src/v8/test/debugger/debug/regress/regress-131994.js +++ b/src/v8/test/debugger/debug/regress/regress-131994.js
@@ -33,7 +33,7 @@ Debug = debug.Debug; -var exception = false; +var exceptionThrown = false; function listener(event, exec_state, event_data, data) { if (event != Debug.DebugEvent.Break) return; @@ -44,7 +44,7 @@ // Assert correct value. assertEquals(3, breakpoint.evaluate('x').value()); } catch (e) { - exception = e; + exceptionThrown = true; } } @@ -67,4 +67,4 @@ h(); -assertFalse(exception); +assertFalse(exceptionThrown);
diff --git a/src/v8/test/debugger/debug/regress/regress-1639.js b/src/v8/test/debugger/debug/regress/regress-1639.js index eaaca51..cf5f8f5 100644 --- a/src/v8/test/debugger/debug/regress/regress-1639.js +++ b/src/v8/test/debugger/debug/regress/regress-1639.js
@@ -27,7 +27,7 @@ Debug = debug.Debug var breaks = 0; -var exception = false; +var exceptionThrown = false; function listener(event, exec_state, event_data, data) { try { @@ -43,7 +43,7 @@ } } catch (e) { print(e); - exception = true; + exceptionThrown = true; } } @@ -72,4 +72,4 @@ a(b); a(); // BREAK 3 -assertFalse(exception); +assertFalse(exceptionThrown);
diff --git a/src/v8/test/debugger/debug/regress/regress-2825.js b/src/v8/test/debugger/debug/regress/regress-2825.js index 01bdddf..720b21c 100644 --- a/src/v8/test/debugger/debug/regress/regress-2825.js +++ b/src/v8/test/debugger/debug/regress/regress-2825.js Binary files differ
diff --git a/src/v8/test/debugger/debug/regress/regress-392114.js b/src/v8/test/debugger/debug/regress/regress-392114.js index b9ca4ed..2661909 100644 --- a/src/v8/test/debugger/debug/regress/regress-392114.js +++ b/src/v8/test/debugger/debug/regress/regress-392114.js
@@ -52,6 +52,7 @@ Debug.setListener(function () {}); var d = create_closure(); +%PrepareFunctionForOptimization(d); %OptimizeFunctionOnNextCall(d); // Thanks to the debugger, we recreate the full code too. We deopt and run // it, stomping on the unexpected AllocationSite in the type vector slot.
diff --git a/src/v8/test/debugger/debug/regress/regress-4309-1.js b/src/v8/test/debugger/debug/regress/regress-4309-1.js index 2e7ef47..ef1aee6 100644 --- a/src/v8/test/debugger/debug/regress/regress-4309-1.js +++ b/src/v8/test/debugger/debug/regress/regress-4309-1.js
@@ -25,6 +25,8 @@ debugger; } +%PrepareFunctionForOptimization(f); + f(); f();
diff --git a/src/v8/test/debugger/debug/regress/regress-4309-2.js b/src/v8/test/debugger/debug/regress/regress-4309-2.js index e93c8ec..698be3c 100644 --- a/src/v8/test/debugger/debug/regress/regress-4309-2.js +++ b/src/v8/test/debugger/debug/regress/regress-4309-2.js
@@ -22,6 +22,8 @@ debugger; } +%PrepareFunctionForOptimization(f); + f(); f();
diff --git a/src/v8/test/debugger/debug/regress/regress-4309-3.js b/src/v8/test/debugger/debug/regress/regress-4309-3.js index 026a7cb..71664d6 100644 --- a/src/v8/test/debugger/debug/regress/regress-4309-3.js +++ b/src/v8/test/debugger/debug/regress/regress-4309-3.js
@@ -27,6 +27,8 @@ } } +%PrepareFunctionForOptimization(f); + f(); f();
diff --git a/src/v8/test/debugger/debug/regress/regress-4320.js b/src/v8/test/debugger/debug/regress/regress-4320.js index 5d88cc3..763a9f3 100644 --- a/src/v8/test/debugger/debug/regress/regress-4320.js +++ b/src/v8/test/debugger/debug/regress/regress-4320.js
@@ -9,6 +9,7 @@ function g() { } +%PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f);
diff --git a/src/v8/test/debugger/debug/regress/regress-514362.js b/src/v8/test/debugger/debug/regress/regress-514362.js index beebf4c..8422c99 100644 --- a/src/v8/test/debugger/debug/regress/regress-514362.js +++ b/src/v8/test/debugger/debug/regress/regress-514362.js
@@ -7,6 +7,7 @@ function foo() { bar(arguments[0]); } function wrap() { return foo(1); } +%PrepareFunctionForOptimization(wrap); wrap(); wrap(); %OptimizeFunctionOnNextCall(wrap);
diff --git a/src/v8/test/debugger/debug/regress/regress-5164.js b/src/v8/test/debugger/debug/regress/regress-5164.js index 2ac9d7a..1da7890 100644 --- a/src/v8/test/debugger/debug/regress/regress-5164.js +++ b/src/v8/test/debugger/debug/regress/regress-5164.js
@@ -27,17 +27,17 @@ foo.next() assertEquals(2, args.length); -assertEquals(undefined, args[0]); -assertEquals(undefined, args[1]); +assertEquals(1, args[0]); +assertEquals(2, args[1]); foo.next() assertEquals(2, args.length); -assertEquals(undefined, args[0]); -assertEquals(undefined, args[1]); +assertEquals(1, args[0]); +assertEquals(2, args[1]); foo.next() assertEquals(2, args.length); -assertEquals(undefined, args[0]); -assertEquals(undefined, args[1]); +assertEquals(1, args[0]); +assertEquals(2, args[1]); assertNull(failure);
diff --git a/src/v8/test/debugger/debug/regress/regress-5279.js b/src/v8/test/debugger/debug/regress/regress-5279.js index 4a30ac5..0f6f96f 100644 --- a/src/v8/test/debugger/debug/regress/regress-5279.js +++ b/src/v8/test/debugger/debug/regress/regress-5279.js
@@ -7,9 +7,14 @@ Debug.setListener(() => undefined); -const myObj = {}; +function f() { + const myObj = {}; -for (let i = 0; i < 10; i++) { - %OptimizeOsr(); - %ScheduleBreak(); + for (let i = 0; i < 10; i++) { + %OptimizeOsr(); + %ScheduleBreak(); + %PrepareFunctionForOptimization(f); + } } +%PrepareFunctionForOptimization(f); +f()
diff --git a/src/v8/test/debugger/debug/regress/regress-9067.js b/src/v8/test/debugger/debug/regress/regress-9067.js new file mode 100644 index 0000000..300c1d2 --- /dev/null +++ b/src/v8/test/debugger/debug/regress/regress-9067.js
@@ -0,0 +1,22 @@ +// Copyright 2019 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. + +// Flags: --expose-gc --stress-flush-bytecode + +var Debug = debug.Debug +var bp; + +Debug.setListener(function (event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + Debug.clearBreakPoint(bp); + gc(); + } +}); + +function f() { + (function () {})(); +} + +bp = Debug.setBreakPoint(f, 0, 0); +f();
diff --git a/src/v8/test/debugger/debug/regress/regress-crbug-323936.js b/src/v8/test/debugger/debug/regress/regress-crbug-323936.js index 391b095..17ffce1 100644 --- a/src/v8/test/debugger/debug/regress/regress-crbug-323936.js +++ b/src/v8/test/debugger/debug/regress/regress-crbug-323936.js
@@ -37,11 +37,16 @@ // and 'e' binds to the exception. function write_0(v) { e = v } function write_1(v) { x = v } + // Make sure write_0 and write_1 are 'used' so that they are visible to the + // debugger. + write_0, write_1; debugger; assertEquals("foo", e); // overwritten by the debugger } assertEquals("argument", e); // debugger did not overwrite function write_2(v) { e = v } + // Make sure write_2 is 'used' so that it is visible to the debugger. + write_2; debugger; assertEquals("bar", e); assertEquals("modified", x);
diff --git a/src/v8/test/debugger/debug/regress/regress-crbug-387599.js b/src/v8/test/debugger/debug/regress/regress-crbug-387599.js index bf15cba..6eee8d7 100644 --- a/src/v8/test/debugger/debug/regress/regress-crbug-387599.js +++ b/src/v8/test/debugger/debug/regress/regress-crbug-387599.js
@@ -7,10 +7,15 @@ Debug.setListener(function() {}); function f() { - for (var i = 0; i < 100; i++) %OptimizeOsr(); + for (var i = 0; i < 100; i++) { + %OptimizeOsr(); + %PrepareFunctionForOptimization(f); + } } +%PrepareFunctionForOptimization(f); Debug.setBreakPoint(f, 0, 0); f(); +%PrepareFunctionForOptimization(f); f(); Debug.setListener(null);
diff --git a/src/v8/test/debugger/debug/regress/regress-crbug-633999.js b/src/v8/test/debugger/debug/regress/regress-crbug-633999.js index ebaabd7..94ca890 100644 --- a/src/v8/test/debugger/debug/regress/regress-crbug-633999.js +++ b/src/v8/test/debugger/debug/regress/regress-crbug-633999.js
@@ -28,6 +28,7 @@ } catch (e) { } } + %PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f);
diff --git a/src/v8/test/debugger/debug/regress/regress-debug-code-recompilation.js b/src/v8/test/debugger/debug/regress/regress-debug-code-recompilation.js index ce6ce86..5223ed6 100644 --- a/src/v8/test/debugger/debug/regress/regress-debug-code-recompilation.js +++ b/src/v8/test/debugger/debug/regress/regress-debug-code-recompilation.js
@@ -34,6 +34,7 @@ b=2; } +%PrepareFunctionForOptimization(Debug.setBreakPoint); bp = Debug.setBreakPoint(f, 0, 0); Debug.clearBreakPoint(bp); %OptimizeFunctionOnNextCall(Debug.setBreakPoint); @@ -41,6 +42,7 @@ Debug.clearBreakPoint(bp); bp = Debug.setBreakPoint(f, 0, 0); Debug.clearBreakPoint(bp); +%PrepareFunctionForOptimization(Debug.setBreakPoint); %OptimizeFunctionOnNextCall(Debug.setBreakPoint); bp = Debug.setBreakPoint(f, 0, 0); Debug.clearBreakPoint(bp);
diff --git a/src/v8/test/debugger/debug/regress/regress-debug-deopt-while-recompile.js b/src/v8/test/debugger/debug/regress/regress-debug-deopt-while-recompile.js index e8336a8..c6b078b 100644 --- a/src/v8/test/debugger/debug/regress/regress-debug-deopt-while-recompile.js +++ b/src/v8/test/debugger/debug/regress/regress-debug-deopt-while-recompile.js
@@ -45,13 +45,16 @@ var bar = "foo"; var baz = bar; // Break point should be here. return bar; -} +}; var g = function() { var bar = "foo"; var baz = bar; // Break point should be here. return bar; -} +}; + +%PrepareFunctionForOptimization(f); +%PrepareFunctionForOptimization(g); f(); f();
diff --git a/src/v8/test/debugger/debug/regress/regress-opt-after-debug-deopt.js b/src/v8/test/debugger/debug/regress/regress-opt-after-debug-deopt.js index 2b11357..b39c97b 100644 --- a/src/v8/test/debugger/debug/regress/regress-opt-after-debug-deopt.js +++ b/src/v8/test/debugger/debug/regress/regress-opt-after-debug-deopt.js
@@ -53,8 +53,9 @@ var b = a.substring("1"); [a, b].sort(); return a; -} +}; +%PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f, "concurrent"); // Mark with builtin.
diff --git a/src/v8/test/debugger/debug/regress/regress-prepare-break-while-recompile.js b/src/v8/test/debugger/debug/regress/regress-prepare-break-while-recompile.js index 3b56254..83d2181 100644 --- a/src/v8/test/debugger/debug/regress/regress-prepare-break-while-recompile.js +++ b/src/v8/test/debugger/debug/regress/regress-prepare-break-while-recompile.js
@@ -45,6 +45,7 @@ return x; } +%PrepareFunctionForOptimization(foo); foo(); foo(); // Mark and kick off recompilation.
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-async.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-async.js new file mode 100644 index 0000000..c7f55c1 --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-async.js
@@ -0,0 +1,59 @@ +// Copyright 2017 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. + +// Test that asynchronous features do not work with +// side-effect free debug-evaluate. + +Debug = debug.Debug + +var exception = null; + +function* generator() { + yield 1; +} + +async function async() { + return 1; +} + +var g = generator(); + +var p = new Promise(() => {}); + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + fail("new Promise()"); + fail("generator()"); + fail("g.next()"); + fail("async()"); + fail("Promise.resolve()"); + fail("Promise.reject()"); + fail("p.then(() => {})"); + fail("p.catch(() => {})"); + fail("p.finally(() => {})"); + fail("Promise.all([p, p])"); + fail("Promise.race([p, p])"); + fail("(async function() {})()"); + fail("(async function() { await 1; })()"); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins-2.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins-2.js new file mode 100644 index 0000000..98cfdb1 --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins-2.js
@@ -0,0 +1,145 @@ +// Copyright 2017 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. + +Debug = debug.Debug + +var exception = null; +var date = new Date(); +var map = new Map().set("a", "b").set("c", "d"); +var set = new Set([1, 2]); +var weak_key = []; +var weak_map = new WeakMap().set(weak_key, "a").set({}, "b"); +var weak_set = new WeakSet([weak_key, {}]); +var add = function (a, b) { return a + b; }; +var number_value = 13; +function get_number() { + return typeof(number_value); +}; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + var result = exec_state.frame(0).evaluate(source, true).value(); + if (expectation !== undefined) assertEquals(expectation, result); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + + // Test Function-related functions. + success("func", `(function func(){}).prototype.constructor.name`); + success("[object Object]", `(function func(){}).prototype.toString()`); + success(12, `add.bind(null, 10)(2)`); + success(3, `add.call(null, 1, 2)`); + success(3, `add.apply(null, [1, 2])`); + + // Test Date.prototype functions. + success(undefined, `Date()`); + success(undefined, `new Date()`); + success(undefined, `Date.now()`); + success(undefined, `Date.parse(1)`); + for (f of Object.getOwnPropertyNames(Date.prototype)) { + if (typeof Date.prototype[f] === "function") { + if (f.startsWith("set")) { + fail(`date.${f}(5);`, true); + } else if (f.startsWith("toLocale") && typeof Intl === "undefined") { + continue; + } else { + success(undefined, `date.${f}();`); + } + } + } + + // Test Boolean. + success(true, `Boolean(1)`); + success(new Boolean(true), `new Boolean(1)`); + success("true", `true.toString()`); + success(true, `true.valueOf()`); + + // Test global functions. + success(1, `parseInt("1")`); + success(1.3, `parseFloat("1.3")`); + success("abc", `decodeURI("abc")`); + success("abc", `encodeURI("abc")`); + success("abc", `decodeURIComponent("abc")`); + success("abc", `encodeURIComponent("abc")`); + success("abc", `escape("abc")`); + success("abc", `unescape("abc")`); + success(true, `isFinite(0)`); + success(true, `isNaN(0/0)`); + success("object", `typeof date`); + success("number", `get_number()`); + + // Test Map functions. + success(undefined, `new Map()`); + success("[object Map]", `map.toString()`); + success("b", `map.get("a")`); + success(true, `map.get("x") === undefined`); + success(undefined, `map.entries()`); + success(undefined, `map.keys()`); + success(undefined, `map.values()`); + success(undefined, `map.forEach(()=>1)`); + success(true, `map.has("c")`); + success(2, `map.size`); + success(undefined, `new Map([[1, 2]])`); + fail(`map.delete("a")`); + fail(`map.clear()`); + fail(`map.set("x", "y")`); + + // Test Set functions. + success(undefined, `new Set()`); + success("[object Set]", `set.toString()`); + success(undefined, `set.entries()`); + success(undefined, `set.keys()`); + success(undefined, `set.values()`); + success(undefined, `set.forEach(()=>1)`); + success(true, `set.has(1)`); + success(2, `set.size`); + success(1, `new Set([1]).size`); + fail(`set.add(2)`); + fail(`set.delete(1)`); + fail(`set.clear()`); + + // Test WeakMap functions. + success(undefined, `new WeakMap()`); + success("[object WeakMap]", `weak_map.toString()`); + success("a", `weak_map.get(weak_key)`); + success(true, `weak_map.get([]) === undefined`); + success(true, `weak_map.has(weak_key)`); + fail(`new WeakMap([[[], {}]])`); + fail(`weak_map.delete("a")`); + fail(`weak_map.set("x", "y")`); + + // Test WeakSet functions. + success(undefined, `new WeakSet()`); + success("[object WeakSet]", `weak_set.toString()`); + success(true, `weak_set.has(weak_key)`); + fail(`new WeakSet([[], {}])`); + fail(`weak_set.add([])`); + fail(`weak_set.delete("a")`); + + // Test BigInt functions. + success(10n, `BigInt('10')`); + success(10n, `BigInt.asIntN(10, 10n)`); + success(10n, `BigInt.asUintN(10, 10n)`); + success("10", `10n.toString()`); + success(10n, `10n.valueOf()`); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins.js new file mode 100644 index 0000000..29d8145 --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-builtins.js
@@ -0,0 +1,234 @@ +// Copyright 2017 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. + +// Flags: --no-enable-one-shot-optimization + +Debug = debug.Debug + +var exception = null; +var object_with_symbol_key = {[Symbol("a")]: 1}; +var object_with_callbacks = { toString: () => "string", valueOf: () => 3}; +var symbol_for_a = Symbol.for("a"); +var typed_array = new Uint8Array([1, 2, 3]); +var array_buffer = new ArrayBuffer(3); +var data_view = new DataView(new ArrayBuffer(8), 0, 8); +var array = [1,2,3]; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + var result = exec_state.frame(0).evaluate(source, true).value(); + if (expectation !== undefined) assertEquals(expectation, result); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + + // Test some Object functions. + success({}, `new Object()`); + success({p : 3}, `Object.create({}, { p: { value: 3 } })`); + success("[[\"a\",1],[\"b\",2]]", + `JSON.stringify(Object.entries({a:1, b:2}))`); + success({value: 1, writable: true, enumerable: true, configurable: true}, + `Object.getOwnPropertyDescriptor({a: 1}, "a")`); + success("{\"a\":{\"value\":1,\"writable\":true," + + "\"enumerable\":true,\"configurable\":true}}", + `JSON.stringify(Object.getOwnPropertyDescriptors({a: 1}))`); + success(["a"], `Object.getOwnPropertyNames({a: 1})`); + success(undefined, `Object.getOwnPropertySymbols(object_with_symbol_key)`); + success({}, `Object.getPrototypeOf(Object.create({}))`); + success(true, `Object.is(Object, Object)`); + success(true, `Object.isExtensible({})`); + success(false, `Object.isFrozen({})`); + success(false, `Object.isSealed({})`); + success([1, 2], `Object.values({a:1, b:2})`); + + fail(`Object.assign({}, {})`); + fail(`Object.defineProperties({}, [{p:{value:3}}])`); + fail(`Object.defineProperty({}, {p:{value:3}})`); + fail(`Object.freeze({})`); + fail(`Object.preventExtensions({})`); + fail(`Object.seal({})`); + fail(`Object.setPrototypeOf({}, {})`); + + // Test some Object.prototype functions. + success(true, `({a:1}).hasOwnProperty("a")`); + success(true, `Object.prototype.isPrototypeOf({})`); + success(true, `({a:1}).propertyIsEnumerable("a")`); + success("[object Object]", `({a:1}).toString()`); + success("[object Object]", `({a:1}).toLocaleString()`); + success("string", `(object_with_callbacks).toString()`); + success(3, `(object_with_callbacks).valueOf()`); + + // Test Array functions. + success(true, `Array.isArray([1, 2, 3])`); + success([], `new Array()`); + success([undefined, undefined], `new Array(2)`); + success([1, 2], `new Array(1, 2)`); + fail(`Array.from([1, 2, 3])`); + fail(`Array.of(1, 2, 3)`); + var function_param = [ + "flatMap", "forEach", "every", "some", "reduce", "reduceRight", "find", + "filter", "map", "findIndex" + ]; + var fails = ["pop", "push", "reverse", "shift", "unshift", "splice", + "sort", "copyWithin", "fill"]; + for (f of Object.getOwnPropertyNames(Array.prototype)) { + if (typeof Array.prototype[f] === "function") { + if (fails.includes(f)) { + if (function_param.includes(f)) { + fail(`array.${f}(()=>{});`); + } else { + fail(`array.${f}();`); + } + } else if (function_param.includes(f)) { + exec_state.frame(0).evaluate(`array.${f}(()=>{});`, true); + } else { + exec_state.frame(0).evaluate(`array.${f}();`, true); + } + } + } + + // Test ArrayBuffer functions. + success(3, `array_buffer.byteLength`); + success(2, `array_buffer.slice(1, 3).byteLength`); + success(true, `ArrayBuffer.isView(typed_array)`); + + // Test DataView functions. + success(undefined, `new DataView(array_buffer, 1, 2)`); + success(undefined, `data_view.buffer`); + success(undefined, `data_view.byteLength`); + success(undefined, `data_view.byteOffset`); + for (f of Object.getOwnPropertyNames(DataView.prototype)) { + if (typeof data_view[f] === 'function') { + if (f.startsWith('getBig')) { + success(0n, `data_view.${f}()`); + } else if (f.startsWith('get')) { + success(0, `data_view.${f}()`); + } + } + } + + // Test TypedArray functions. + success({}, `new Uint8Array()`); + success({0: 0, 1: 0}, `new Uint8Array(2)`); + success({0: 1, 1: 2, 2: 3}, `new Uint8Array(typed_array)`); + success(true, `!!typed_array.buffer`); + success(0, `typed_array.byteOffset`); + success(3, `typed_array.byteLength`); + fail(`Uint8Array.of(1, 2)`); + function_param = [ + "forEach", "every", "some", "reduce", "reduceRight", "find", "filter", + "map", "findIndex" + ]; + fails = ["reverse", "sort", "copyWithin", "fill", "set"]; + var typed_proto_proto = Object.getPrototypeOf(Object.getPrototypeOf(new Uint8Array())); + for (f of Object.getOwnPropertyNames(typed_proto_proto)) { + if (typeof typed_array[f] === "function" && f !== "constructor") { + if (fails.includes(f)) { + if (function_param.includes(f)) { + fail(`typed_array.${f}(()=>{});`); + } else { + fail(`typed_array.${f}();`); + } + } else if (function_param.includes(f)) { + exec_state.frame(0).evaluate(`typed_array.${f}(()=>{});`, true); + } else { + exec_state.frame(0).evaluate(`typed_array.${f}();`, true); + } + } + } + + // Test Math functions. + for (f of Object.getOwnPropertyNames(Math)) { + if (typeof Math[f] === "function") { + var result = exec_state.frame(0).evaluate( + `Math.${f}(0.5, -0.5);`, true).value(); + if (f != "random") assertEquals(Math[f](0.5, -0.5), result); + } + } + + // Test Number functions. + success(new Number(0), `new Number()`); + for (f of Object.getOwnPropertyNames(Number)) { + if (typeof Number[f] === "function") { + success(Number[f](0.5), `Number.${f}(0.5);`); + } + } + for (f of Object.getOwnPropertyNames(Number.prototype)) { + if (typeof Number.prototype[f] === "function") { + if (f == "toLocaleString" && typeof Intl === "undefined") continue; + success(Number(0.5)[f](5), `Number(0.5).${f}(5);`); + } + } + + // Test String functions. + success(new String(), `new String()`); + success(" ", "String.fromCodePoint(0x20)"); + success(" ", "String.fromCharCode(0x20)"); + for (f of Object.getOwnPropertyNames(String.prototype)) { + if (typeof String.prototype[f] === "function") { + // Do not expect locale-specific or regexp-related functions to work. + // {Lower,Upper}Case (Locale-specific or not) do not work either + // if Intl is enabled. + if (f.indexOf("locale") >= 0) continue; + if (f.indexOf("Locale") >= 0) continue; + if (typeof Intl !== 'undefined') { + if (f == "toUpperCase") continue; + if (f == "toLowerCase") continue; + } + if (f == "normalize") continue; + if (f == "match") continue; + if (f == "matchAll") continue; + if (f == "search") continue; + if (f == "split" || f == "replace") { + fail(`'abcd'.${f}(2)`); + continue; + } + success("abcd"[f](2), `"abcd".${f}(2);`); + } + } + fail("'abCd'.toLocaleLowerCase()"); + fail("'abcd'.toLocaleUpperCase()"); + if (typeof Intl !== 'undefined') { + fail("'abCd'.toLowerCase()"); + fail("'abcd'.toUpperCase()"); + } + fail("'abcd'.match(/a/)"); + fail("'abcd'.replace(/a/)"); + fail("'abcd'.search(/a/)"); + + // Test RegExp functions. + fail(`/a/.compile()`); + success('a', `/a/.exec('abc')[0]`); + success(true, `/a/.test('abc')`); + fail(`/a/.toString()`); + + // Test JSON functions. + success('{"abc":[1,2]}', "JSON.stringify(JSON.parse('{\"abc\":[1,2]}'))"); + + // Test Symbol functions. + success(undefined, `Symbol("a")`); + fail(`Symbol.for("a")`); // Symbol.for can be observed via Symbol.keyFor. + success("a", `Symbol.keyFor(symbol_for_a)`); + success("Symbol(a)", `symbol_for_a.valueOf().toString()`); + success("Symbol(a)", `symbol_for_a[Symbol.toPrimitive]().toString()`); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-control.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-control.js new file mode 100644 index 0000000..06f41eb --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-control.js
@@ -0,0 +1,109 @@ +// Copyright 2017 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. + +Debug = debug.Debug + +var exception = null; + +var o = { p : 1 }; + +var successes = [ + [45, + `(function() { + var sum = 0; + for (var i = 0; i < 10; i++) sum += i; + return sum; + })()` + ], + ["0012", + `(function() { + var sum = 0; + for (var i in [1, 2, 3]) sum += i; + return sum; + })()` + ], + [15, + `(function() { + var sum = 1; + while (sum < 12) sum += sum + 1; + return sum; + })()` + ], + [15, + `(function() { + var sum = 1; + do { sum += sum + 1; } while (sum < 12); + return sum; + })()` + ], + ["023", + `(function() { + var sum = ""; + for (var i = 0; i < 4; i++) { + switch (i) { + case 0: + case 1: + if (i == 0) sum += i; + break; + default: + case 3: + sum += i; + break; + } + } + return sum; + })()` + ], + ["oups", + `(function() { + try { + if (Math.sin(1) < 1) throw new Error("oups"); + } catch (e) { + return e.message; + } + })()` + ], + [6, + `(function() { // Iterator.prototype.next performs stores. + var sum = 0; + for (let i of [1, 2, 3]) sum += i; + return sum; + })()` + ] +]; + +var fails = [ + `(function() { // Store to scope object. + with (o) { + p = 2; + } + })()`, +]; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + successes.forEach(function ([expectation, source]) { + assertEquals(expectation, + exec_state.frame(0).evaluate(source, true).value()); + }); + fails.forEach(function (test) { + assertThrows(() => exec_state.frame(0).evaluate(test, true), EvalError); + }); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-iife.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-iife.js new file mode 100644 index 0000000..c8dc2a5 --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-iife.js
@@ -0,0 +1,67 @@ +// Copyright 2017 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. + +// Test that declaring local variables in IIFEs works with +// side-effect free debug-evaluate. + +Debug = debug.Debug + +var exception = null; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + assertEquals(expectation, + exec_state.frame(0).evaluate(source, true).value()); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + // Declaring 'a' sets a property to the global object. + fail("var a = 3"); + exec_state.frame(0).evaluate("var a = 2", false); + assertEquals(2, a); + // Wrapping into an IIFE would be fine, since 'a' is local. + success(100, + `(function(x) { + var a = 0; + for (var i = 0; i < x; i++) { + a += x; + } + return a; + })(10);`); + success(100, + `(x => { + let a = 0; + for (var i = 0; i < x; i++) { + a += x; + } + return a; + })(10);`); + // Not using 'var' to declare would make the access go to global object. + fail( `(function(x) { + a = 0; + for (var i = 0; i < x; i++) { + a += x; + } + return a; + })(10);`); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-ops.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-ops.js new file mode 100644 index 0000000..7f3675d --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-ops.js
@@ -0,0 +1,97 @@ +// Copyright 2017 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. + +Debug = debug.Debug + +var exception = null; +var date = new Date(); +var T = true; +var F = false; +var one = 1; +var two = 2; +var string = "s"; +var array = [1, 2, 3]; +function max(...rest) { + return Math.max(...rest); +} + +function def(a = 1) { + return a; +} + +function d1([a, b = 'b']) { + return a + b; +} + +function d2({ x: c, y, z = 'z' } = {x: 'x', y: 'y' }) { + return c + y + z; +} + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + var result = exec_state.frame(0).evaluate(source, true).value(); + if (expectation !== undefined) assertEquals(expectation, result); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + success(false, `Object == {}`); + success(false, `Object === {}`); + success(true, `Object != {}`); + success(true, `Object !== {}`); + success(true, `'s' == string`); + success(true, `'s' === string`); + success(true, `1 < Math.cos(0) * 2`); + success(false, `1 < string`); + success(true, `'a' < string`); + success("s", `string[0]`); + success(0, `[0][0]`); + success(1, `T^F`); + success(0, `T&F`); + success(1, `T|F`); + success(false, `T&&F`); + success(true, `T||F`); + success(false, `T?F:T`); + success(false, `!T`); + success(1, `+one`); + success(-1, `-one`); + success(-2, `~one`); + success(4, `one << two`); + success(1, `two >> one`); + success(1, `two >>> one`); + success(3, `two + one`); + success(2, `two * one`); + success(0.5, `one / two`); + success(0, `(one / two) | 0`); + success(1, `one ** two`); + success(NaN, `string * two`); + success("s2", `string + two`); + success("s2", `string + two`); + success([1,2,3], `[...array]`); + success(3, `max(...array)`); + success({s:1}, `({[string]:1})`); + fail(`[a, b] = [1, 2]`); + success(2, `def(2)`); + success(1, `def()`); + success('ab', `d1(['a'])`); + success("XYz", `d2({x:'X', y:'Y'})`); + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-regexp.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-regexp.js new file mode 100644 index 0000000..1db5dbd --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-regexp.js
@@ -0,0 +1,28 @@ +// Copyright 2018 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. + +Debug = debug.Debug; + +/(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)(\w)/.exec(">>>abcdefghij<<<"); +assertRegExp(); +Debug.evaluateGlobal(`/(\\w)(\\w)(\\w)(\\w)(\\w)(\\w)(\\w)(\\w)(\\w)(\\w)/.exec(">>>hklmnoprst<<<")`, true); +assertRegExp(); + +function assertRegExp() { + assertEquals("a", RegExp.$1); + assertEquals("b", RegExp.$2); + assertEquals("c", RegExp.$3); + assertEquals("d", RegExp.$4); + assertEquals("e", RegExp.$5); + assertEquals("f", RegExp.$6); + assertEquals("g", RegExp.$7); + assertEquals("h", RegExp.$8); + assertEquals("i", RegExp.$9); + + assertEquals("abcdefghij", RegExp.lastMatch); + assertEquals("j", RegExp.lastParen); + assertEquals(">>>", RegExp.leftContext); + assertEquals("<<<", RegExp.rightContext); + assertEquals(">>>abcdefghij<<<", RegExp.input); +}
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-runtime-check.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-runtime-check.js new file mode 100644 index 0000000..7a0f373 --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect-runtime-check.js
@@ -0,0 +1,201 @@ +// Copyright 2018 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. + +Debug = debug.Debug; + +// StaCurrentContextSlot +success(10, `(function(){ + const x = 10; + function f1() {return x;} + return x; +})()`); + +// StaNamedProperty +var a = {name: 'foo'}; +function set_name(a) { + a.name = 'bar'; + return a.name; +} + +fail(`set_name(a)`); +success('bar', `set_name({name: 'foo'})`); + +// StaNamedOwnProperty +var name_value = 'value'; +function create_object_literal() { + var obj = {name: name_value}; + return obj.name; +}; + +success('value', `create_object_literal()`); + +// StaKeyedProperty +var arrayValue = 1; +function create_array_literal() { + return [arrayValue]; +} +var b = { 1: 2 }; + +success([arrayValue], `create_array_literal()`) +fail(`b[1] ^= 2`); + +// StaInArrayLiteral +function return_array_use_spread(a) { + return [...a]; +} + +success([1], `return_array_use_spread([1])`); + +// CallAccessorSetter +var array = [1,2,3]; +fail(`array.length = 2`); +success(2, `[1,2,3].length = 2`); + +// StaDataPropertyInLiteral +function return_literal_with_data_property(a) { + return {[a] : 1}; +} + +success({foo: 1}, `return_literal_with_data_property('foo')`); + +// Set builtins with temporary objects +var set = new Set([1,2]); +fail(`set.add(3).size`); +success(1, `new Set().add(1).size`); + +success(0, `(() => { const s = new Set([1]); s.delete(1); return s.size; })()`); +fail(`set.delete(1)`); + +success(0, `(() => { const s = new Set([1]); s.clear(); return s.size; })()`); +fail(`set.clear()`); + +// new set +success(3, `(() => { + let s = 0; + for (const a of new Set([1,2])) + s += a; + return s; +})()`); +// existing set +success(3, `(() => { + let s = 0; + for (const a of set) + s += a; + return s; +})()`); +// existing iterator +var setIterator = set.entries(); +fail(`(() => { + let s = 0; + for (const a of setIterator) + s += a; + return s; +})()`); + +// Array builtins with temporary objects +success([1,1,1], '[1,2,3].fill(1)'); +fail(`array.fill(1)`); + +success([1], `(() => { const a = []; a.push(1); return a; })()`); +fail(`array.push(1)`); + +success([1], `(() => { const a = [1,2]; a.pop(); return a; })()`); +fail(`array.pop()`); + +success([3,2,1], `[1,2,3].reverse()`); +fail(`array.reverse()`); + +success([1,2,3], `[2,1,3].sort()`); +fail(`array.sort()`); + +success([2,3], `[1,2,3].splice(1,2)`); +fail(`array.splice(1,2)`); + +success([1,2], `(() => { const a = [2]; a.unshift(1); return a; })()`); +fail(`array.unshift(1)`); +success(1, `[1,2].shift()`); +fail(`array.shift()`); + +// new array +success(6, `(() => { + let s = 0; + for (const a of [1,2,3]) + s += a; + return s; +})()`); +// existing array +success(6, `(() => { + let s = 0; + for (const a of array) + s += a; + return s; +})()`); +// existing iterator +var arrayIterator = array.entries(); +fail(`(() => { + let s = 0; + for (const a of arrayIterator) + s += a; + return s; +})()`); + +success(6, `array.reduce((a,b) => a + b, 0)`); + +// Map builtins with temporary objects +var map = new Map([[1,2]]); +fail(`map.set(3, 4).size`); +success(1, `new Map().set(1, 2).size`); + +success(0, `(() => { + const m = new Map([[1, 2]]); + m.delete(1); + return m.size; +})()`); +fail(`map.delete(1)`); + +success(0, `(() => { + const m = new Map([[1, 2]]); + m.clear(); + return m.size; +})()`); +fail(`map.clear()`); + +// new set +success(2, `(() => { + let s = 0; + for (const [a, b] of new Map([[1,2]])) + s += b; + return s; +})()`); +// existing set +success(2, `(() => { + let s = 0; + for (const [a,b] of map) + s += b; + return s; +})()`); +// existing iterator +var mapIterator = map.entries(); +fail(`(() => { + let s = 0; + for (const [a,b] of mapIterator) + s += a; + return s; +})()`); + +// Regexps +var regExp = /a/; +success(true, `/a/.test('a')`); +fail(`/a/.test({toString: () => {map.clear(); return 'a';}})`) +fail(`regExp.test('a')`); + +function success(expectation, source) { + const result = Debug.evaluateGlobal(source, true).value(); + if (expectation !== undefined) assertEquals(expectation, result); +} + +function fail(source) { + assertThrows(() => Debug.evaluateGlobal(source, true), + EvalError); +}
diff --git a/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect.js b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect.js new file mode 100644 index 0000000..5504cef --- /dev/null +++ b/src/v8/test/debugger/debug/side-effect/debug-evaluate-no-side-effect.js
@@ -0,0 +1,131 @@ +// Copyright 2017 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. + +Debug = debug.Debug + +var exception = null; +let a = 1; +var object = { property : 2, + get getter() { return 3; } + }; +var string0 = new String("string"); +var string1 = { toString() { return "x"; } }; +var string2 = { toString() { print("x"); return "x"; } }; +var array = [4, 5]; +var error = new Error(); + +function simple_return(x) { return x; } +function set_a() { a = 2; } +function get_a() { return a; } +var bound = get_a.bind(0); + +function return_arg0() { return return_arg0.arguments[0]; } +function return_caller_name() { return return_caller_name.caller.name; } + +var global_eval = eval; + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + assertEquals(expectation, + exec_state.frame(0).evaluate(source, true).value()); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + + // Simple test. + success(3, "1 + 2"); + // Dymanic load. + success(array, "array"); + // Context load. + success(1, "a"); + // Global and named property load. + success(2, "object.property"); + // Load via read-only getter. + success(3, "object.getter"); + // Implicit call to read-only toString. + success("xy", "string1 + 'y'"); + // Keyed property load. + success(5, "array[1]"); + // Call to read-only function. + success(1, "get_a()"); + success(1, "bound()"); + success({}, "new get_a()"); + // Call to read-only function within try-catch. + success(1, "try { get_a() } catch (e) {}"); + // Call to C++ built-in. + success(Math.sin(2), "Math.sin(2)"); + // Call to whitelisted get accessors. + success(3, "'abc'.length"); + success(2, "array.length"); + success(1, "'x'.length"); + success(0, "set_a.length"); + success("set_a", "set_a.name"); + success(0, "bound.length"); + success("bound get_a", "bound.name"); + success(1, "return_arg0(1)"); + success("f", "(function f() { return return_caller_name() })()"); + // Non-evaluated call. + // Constructed literals. + success([1], "[1]"); + success({x: 1}, "({x: 1})"); + success([1], "[a]"); + success({x: 1}, "({x: a})"); + // Test that template literal evaluation fails. + fail("simple_return`1`"); + // Test that non-read-only code fails. + fail("exception = 1"); + // Test that calling a non-read-only function fails. + fail("set_a()"); + fail("new set_a()"); + // Test that implicit call to a non-read-only function fails. + fail("string2 + 'y'"); + // Test that try-catch does not catch the EvalError. + fail("try { set_a() } catch (e) {}"); + // Test that call to set accessor fails. + fail("array.length = 4"); + fail("set_a.name = 'set_b'"); + fail("set_a.length = 1"); + fail("bound.name = 'bound'"); + fail("bound.length = 1"); + fail("set_a.prototype = null"); + // Test that call to non-whitelisted get accessor fails. + fail("error.stack"); + // Call to set accessors with receiver check. + success(1, "[].length = 1"); + success(1, "'x'.length = 1"); + fail("string0.length = 1"); + success(1, "(new String('abc')).length = 1"); + success("g", "(function(){}).name = 'g'"); + success(1, "(function(){}).length = 1"); + success("g", "get_a.bind(0).name = 'g'"); + success(1, "get_a.bind(0).length = 1"); + success(null, "(function(){}).prototype = null"); + success(true, "(new Error()).stack.length > 1"); + success("a", "(new Error()).stack = 'a'"); + // Eval is not allowed. + fail("eval('Math.sin(1)')"); + fail("eval('exception = 1')"); + fail("global_eval('1')"); + success(1, "(() => { var a = 1; return a++; })()") + } catch (e) { + exception = e; + print(e, e.stack); + }; +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception); +assertEquals(1, a);
diff --git a/src/v8/test/debugger/debug/wasm/frame-inspection.js b/src/v8/test/debugger/debug/wasm/frame-inspection.js index 45fa8a9..882b7e3 100644 --- a/src/v8/test/debugger/debug/wasm/frame-inspection.js +++ b/src/v8/test/debugger/debug/wasm/frame-inspection.js
@@ -4,7 +4,6 @@ // Flags: --expose-wasm -load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-module-builder.js"); Debug = debug.Debug @@ -25,7 +24,6 @@ if (event != Debug.DebugEvent.Break) return; ++break_count; try { - var break_id = exec_state.break_id; var frame_count = exec_state.frameCount(); assertEquals(expected_frames.length, frame_count, 'frame count');
diff --git a/src/v8/test/debugger/debugger.status b/src/v8/test/debugger/debugger.status index 98a95eb..503e5e7 100644 --- a/src/v8/test/debugger/debugger.status +++ b/src/v8/test/debugger/debugger.status
@@ -18,8 +18,9 @@ 'debug/es6/debug-promises/reject-with-invalid-reject': [FAIL], # Issue 5651: Context mismatch in ScopeIterator::Type() for eval default - # parameter value - 'debug/es6/debug-scope-default-param-with-eval': [FAIL], + # parameter value (the test causes indexing a FixedArray out of bounds -> + # CRASH is also a reasonable outcome). + 'debug/es6/debug-scope-default-param-with-eval': [FAIL, CRASH], # Slow tests 'debug/debug-scopes': [PASS, SLOW], @@ -44,6 +45,12 @@ }], # variant == stress ############################################################################## +['variant == stress and (arch == arm or arch == arm64) and simulator_run', { + # Slow tests: https://crbug.com/v8/7783 + 'debug/debug-stepout-scope-part*': [SKIP], +}], # variant == stress and (arch == arm or arch == arm64) and simulator_run + +############################################################################## ['variant == stress_incremental_marking', { # BUG(chromium:772010). 'debug/debug-*': [PASS, ['system == windows', SKIP]], @@ -53,14 +60,7 @@ ['gc_stress == True', { # Skip tests not suitable for GC stress. # Tests taking too long - 'debug/debug-stepout-scope-part1': [SKIP], - 'debug/debug-stepout-scope-part2': [SKIP], - 'debug/debug-stepout-scope-part3': [SKIP], - 'debug/debug-stepout-scope-part4': [SKIP], - 'debug/debug-stepout-scope-part5': [SKIP], - 'debug/debug-stepout-scope-part6': [SKIP], - 'debug/debug-stepout-scope-part7': [SKIP], - 'debug/debug-stepout-scope-part8': [SKIP], + 'debug/debug-stepout-scope-part*': [SKIP], # Async function tests taking too long # https://bugs.chromium.org/p/v8/issues/detail?id=5411 @@ -69,12 +69,31 @@ 'debug/es8/async-debug-caught-exception-cases2': [SKIP], 'debug/es8/async-debug-caught-exception-cases3': [SKIP], 'debug/es8/async-function-debug-scopes': [SKIP], + + # https://crbug.com/v8/8141 + 'debug/debug-liveedit-1': [SKIP], + 'debug/debug-liveedit-double-call': [SKIP], + 'debug/es6/debug-liveedit-new-target-3': [SKIP], + 'debug/side-effect/debug-evaluate-no-side-effect-control': [SKIP], }], # 'gc_stress == True' ############################################################################## -['variant == wasm_traps', { +['gc_fuzzer', { + # Slow tests. + 'regress/regress-2318': [SKIP], +}], # 'gc_fuzzer' + +############################################################################## +['predictable == True', { + # https://crbug.com/v8/8147 + 'debug/debug-liveedit-*': [SKIP], + 'debug/debug-set-variable-value': [SKIP], +}], # 'predictable == True' + +############################################################################## +['variant == no_wasm_traps', { '*': [SKIP], -}], # variant == wasm_traps +}], # variant == no_wasm_traps ############################################################################## ['arch == arm and not simulator_run', { @@ -83,13 +102,38 @@ }], # 'arch == arm and not simulator_run' ############################################################################## +['arch == arm and mode == debug', { + # Tests taking too long + 'debug/debug-stepout-scope-part1': [SKIP], + 'debug/debug-stepout-scope-part2': [SKIP], + 'debug/debug-stepout-scope-part3': [SKIP], + 'debug/debug-stepout-scope-part4': [SKIP], + 'debug/debug-stepout-scope-part5': [SKIP], + 'debug/debug-stepout-scope-part6': [SKIP], + 'debug/debug-stepout-scope-part7': [SKIP], + 'debug/debug-stepout-scope-part8': [SKIP], +}], # 'arch == arm and mode == debug' + +############################################################################## ['arch == s390 or arch == s390x', { # Stack manipulations in LiveEdit is not implemented for this arch. 'debug/debug-liveedit-check-stack': [SKIP], 'debug/debug-liveedit-double-call': [SKIP], - 'debug/debug-liveedit-stack-padding': [SKIP], 'debug/debug-liveedit-restart-frame': [SKIP], }], # 'arch == s390 or arch == s390x' +############################################################################## +['lite_mode or variant == jitless', { + # TODO(v8:7777): Re-enable once wasm is supported in jitless mode. + 'debug/wasm/*': [SKIP], + 'regress/regress-crbug-840288': [SKIP], + 'wasm-*': [SKIP], +}], # lite_mode or variant == jitless + +############################################################################## +['variant == jitless and not embedded_builtins', { + '*': [SKIP], +}], # variant == jitless and not embedded_builtins + ]
diff --git a/src/v8/test/debugger/regress/regress-1639-2.js b/src/v8/test/debugger/regress/regress-1639-2.js index 566e2bb..be720d2 100644 --- a/src/v8/test/debugger/regress/regress-1639-2.js +++ b/src/v8/test/debugger/regress/regress-1639-2.js
@@ -27,7 +27,7 @@ // Get the Debug object exposed from the debug context global object. Debug = debug.Debug -var exception = false; +var exceptionThrown = false; var state = 0; function listener(event, exec_state, event_data, data) { @@ -57,7 +57,7 @@ } } catch (e) { print(e); - exception = true; + exceptionThrown = true; } } @@ -70,4 +70,4 @@ // Set a break point and call to invoke the debug event listener. Debug.setBreakPoint(a, 0, 0); a(); -assertFalse(exception); +assertFalse(exceptionThrown);
diff --git a/src/v8/test/debugger/regress/regress-5610.js b/src/v8/test/debugger/regress/regress-5610.js index 7736c04..d59b27e 100644 --- a/src/v8/test/debugger/regress/regress-5610.js +++ b/src/v8/test/debugger/regress/regress-5610.js
@@ -23,9 +23,10 @@ async function f() { var a = 1; - debugger; // B0 StepNext - print(1); // B1 StepNext - return a; // B2 StepNext -} // B3 Continue + debugger; // B0 StepNext + print(1); // B1 StepNext + return a + // B2 StepNext + 0; // B3 Continue +} f();
diff --git a/src/v8/test/debugger/regress/regress-5901-1.js b/src/v8/test/debugger/regress/regress-5901-1.js index 0edffe7..1902767 100644 --- a/src/v8/test/debugger/regress/regress-5901-1.js +++ b/src/v8/test/debugger/regress/regress-5901-1.js
@@ -18,6 +18,7 @@ return g(); } +%PrepareFunctionForOptimization(h); h(); h();
diff --git a/src/v8/test/debugger/regress/regress-5901-2.js b/src/v8/test/debugger/regress/regress-5901-2.js index cf6f0ef..1614ac9 100644 --- a/src/v8/test/debugger/regress/regress-5901-2.js +++ b/src/v8/test/debugger/regress/regress-5901-2.js
@@ -15,6 +15,7 @@ return g(); } +%PrepareFunctionForOptimization(h); h(); h();
diff --git a/src/v8/test/debugger/regress/regress-5950.js b/src/v8/test/debugger/regress/regress-5950.js index 9f0ea5b..8f0d03c 100644 --- a/src/v8/test/debugger/regress/regress-5950.js +++ b/src/v8/test/debugger/regress/regress-5950.js
@@ -15,6 +15,7 @@ return g(); } +%PrepareFunctionForOptimization(h); h(); h();
diff --git a/src/v8/test/debugger/regress/regress-6526.js b/src/v8/test/debugger/regress/regress-6526.js index 90df244..80a82b2 100644 --- a/src/v8/test/debugger/regress/regress-6526.js +++ b/src/v8/test/debugger/regress/regress-6526.js
@@ -16,8 +16,9 @@ } catch (e) { } }); -} +}; +%PrepareFunctionForOptimization(f); f(); f(); %OptimizeFunctionOnNextCall(f);
diff --git a/src/v8/test/debugger/regress/regress-7421.js b/src/v8/test/debugger/regress/regress-7421.js new file mode 100644 index 0000000..dfac06d --- /dev/null +++ b/src/v8/test/debugger/regress/regress-7421.js
@@ -0,0 +1,83 @@ +// Copyright 2018 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. + +// Flags: --block-concurrent-recompilation + +Debug = debug.Debug + +// Test that the side-effect check is not bypassed in optimized code. + +var exception = null; +var counter = 0; + +function f1() { + counter++; +} + +function wrapper1() { + for (var i = 0; i < 4; i++) { + // Get this function optimized before calling to increment. + // Check that that call performs the necessary side-effect checks. + %OptimizeOsr(); + %PrepareFunctionForOptimization(wrapper1); + } + f1(); +} +%PrepareFunctionForOptimization(wrapper1); + +function f2() { + counter++; +} + +function wrapper2(call) { + if (call) f2(); +} + +function listener(event, exec_state, event_data, data) { + if (event != Debug.DebugEvent.Break) return; + try { + function success(expectation, source) { + assertEquals(expectation, + exec_state.frame(0).evaluate(source, true).value()); + } + function fail(source) { + assertThrows(() => exec_state.frame(0).evaluate(source, true), + EvalError); + } + wrapper1(); + wrapper1(); + fail("wrapper1()"); + + %PrepareFunctionForOptimization(wrapper2); + wrapper2(true); + wrapper2(false); + wrapper2(true); + %OptimizeFunctionOnNextCall(wrapper2); + wrapper2(false); + fail("wrapper2(true)"); + fail("%PrepareFunctionForOptimization(wrapper2); "+ + "%OptimizeFunctionOnNextCall(wrapper2); wrapper2(true)"); + + %PrepareFunctionForOptimization(wrapper2); + %OptimizeFunctionOnNextCall(wrapper2, "concurrent"); + wrapper2(false); + fail("%UnblockConcurrentRecompilation();" + + "%GetOptimizationStatus(wrapper2, 'sync');" + + "wrapper2(true);"); + } catch (e) { + exception = e; + print(e, e.stack); + } +}; + +// Add the debug event listener. +Debug.setListener(listener); + +function f() { + debugger; +}; + +f(); + +assertNull(exception);
diff --git a/src/v8/test/debugger/regress/regress-crbug-507070.js b/src/v8/test/debugger/regress/regress-crbug-507070.js new file mode 100644 index 0000000..1ca452f --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-507070.js
@@ -0,0 +1,20 @@ +// Copyright 2015 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. + +// Flags: --allow-natives-syntax --cache=code --no-debug-code + +try { } catch(e) { } +try { try { } catch (e) { } } catch(e) { } +try { + var Debug = debug.Debug; + Debug.setListener(function(){}); +} catch(e) { } +(function() { + Debug.setBreakPoint(function(){}, 0, 0); +})(); + +var a = 1; +a += a; +Debug.setListener(null); +assertEquals(2, a);
diff --git a/src/v8/test/debugger/regress/regress-crbug-736758.js b/src/v8/test/debugger/regress/regress-crbug-736758.js index d483af2..551b0d7 100644 --- a/src/v8/test/debugger/regress/regress-crbug-736758.js +++ b/src/v8/test/debugger/regress/regress-crbug-736758.js
@@ -8,6 +8,7 @@ function f() { [1,2,3].forEach(g) } function g() { debugger } +%PrepareFunctionForOptimization(f); f(); f(); Debug.setListener(listener);
diff --git a/src/v8/test/debugger/regress/regress-crbug-760225.js b/src/v8/test/debugger/regress/regress-crbug-760225.js new file mode 100644 index 0000000..8669714 --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-760225.js
@@ -0,0 +1,30 @@ +// Copyright 2019 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. + +Debug = debug.Debug + +let thisValue; +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.Break) { + thisValue = exec_state.frame(0).evaluate('this').value(); + } +}; + +Debug.setListener(listener); + +class Foo {} +class Bar extends Foo { + constructor() { + super(); + var b = () => this; + this.c = 'b'; // <-- Inspect 'this' (it will be undefined) + debugger; + } +} + +new Bar(); + +Debug.setListener(null); + +assertNotEquals(undefined, thisValue);
diff --git a/src/v8/test/debugger/regress/regress-crbug-808973.js b/src/v8/test/debugger/regress/regress-crbug-808973.js new file mode 100644 index 0000000..e61cb3b --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-808973.js
@@ -0,0 +1,18 @@ +// Copyright 2018 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. + +// Flags: --allow-natives-syntax --enable-inspector + +const Debug = debug.Debug; +Debug.setListener(() => {}); +Debug.setBreakOnUncaughtException() + +function sleep() { + return new Promise(resolve => setTimeout(resolve, 1)); +} +async function thrower() { + await sleep(); + throw "a"; // Exception a +} +(async function() { thrower(); })();
diff --git a/src/v8/test/debugger/regress/regress-crbug-835973.js b/src/v8/test/debugger/regress/regress-crbug-835973.js new file mode 100644 index 0000000..c2df20c --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-835973.js
@@ -0,0 +1,289 @@ +// Copyright 2018 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. + +// Test that stepping works correctly with bytecode scaling prefix. +class MyClass { f(p) { this.x += p; } }; + +let obj = new MyClass(); + +function foo() { + obj.f(0); + obj.f(1); + obj.f(2); + obj.f(3); + obj.f(4); + obj.f(5); + obj.f(6); + obj.f(7); + obj.f(8); + obj.f(9); + obj.f(10); + obj.f(11); + obj.f(12); + obj.f(13); + obj.f(14); + obj.f(15); + obj.f(16); + obj.f(17); + obj.f(18); + obj.f(19); + obj.f(20); + obj.f(21); + obj.f(22); + obj.f(23); + obj.f(24); + obj.f(25); + obj.f(26); + obj.f(27); + obj.f(28); + obj.f(29); + obj.f(30); + obj.f(31); + obj.f(32); + obj.f(33); + obj.f(34); + obj.f(35); + obj.f(36); + obj.f(37); + obj.f(38); + obj.f(39); + obj.f(40); + obj.f(41); + obj.f(42); + obj.f(43); + obj.f(44); + obj.f(45); + obj.f(46); + obj.f(47); + obj.f(48); + obj.f(49); + obj.f(50); + obj.f(51); + obj.f(52); + obj.f(53); + obj.f(54); + obj.f(55); + obj.f(56); + obj.f(57); + obj.f(58); + obj.f(59); + obj.f(60); + obj.f(61); + obj.f(62); + obj.f(63); + obj.f(64); + obj.f(65); + obj.f(66); + obj.f(67); + obj.f(68); + obj.f(69); + obj.f(70); + obj.f(71); + obj.f(72); + obj.f(73); + obj.f(74); + obj.f(75); + obj.f(76); + obj.f(77); + obj.f(78); + obj.f(79); + obj.f(80); + obj.f(81); + obj.f(82); + obj.f(83); + obj.f(84); + obj.f(85); + obj.f(86); + obj.f(87); + obj.f(88); + obj.f(89); + obj.f(90); + obj.f(91); + obj.f(92); + obj.f(93); + obj.f(94); + obj.f(95); + obj.f(96); + obj.f(97); + obj.f(98); + obj.f(99); + obj.f(100); + obj.f(101); + obj.f(102); + obj.f(103); + obj.f(104); + obj.f(105); + obj.f(106); + obj.f(107); + obj.f(108); + obj.f(109); + obj.f(110); + obj.f(111); + obj.f(112); + obj.f(113); + obj.f(114); + obj.f(115); + obj.f(116); + obj.f(117); + obj.f(118); + obj.f(119); + obj.f(120); + obj.f(121); + obj.f(122); + obj.f(123); + obj.f(124); + obj.f(125); + obj.f(126); + obj.f(127); + obj.f(128); + obj.f(129); + obj.f(130); + obj.f(131); + obj.f(132); + obj.f(133); + obj.f(134); + obj.f(135); + obj.f(136); + obj.f(137); + obj.f(138); + obj.f(139); + obj.f(140); + obj.f(141); + obj.f(142); + obj.f(143); + obj.f(144); + obj.f(145); + obj.f(146); + obj.f(147); + obj.f(148); + obj.f(149); + obj.f(150); + obj.f(151); + obj.f(152); + obj.f(153); + obj.f(154); + obj.f(155); + obj.f(156); + obj.f(157); + obj.f(158); + obj.f(159); + obj.f(160); + obj.f(161); + obj.f(162); + obj.f(163); + obj.f(164); + obj.f(165); + obj.f(166); + obj.f(167); + obj.f(168); + obj.f(169); + obj.f(170); + obj.f(171); + obj.f(172); + obj.f(173); + obj.f(174); + obj.f(175); + obj.f(176); + obj.f(177); + obj.f(178); + obj.f(179); + obj.f(180); + obj.f(181); + obj.f(182); + obj.f(183); + obj.f(184); + obj.f(185); + obj.f(186); + obj.f(187); + obj.f(188); + obj.f(189); + obj.f(190); + obj.f(191); + obj.f(192); + obj.f(193); + obj.f(194); + obj.f(195); + obj.f(196); + obj.f(197); + obj.f(198); + obj.f(199); + obj.f(200); + obj.f(201); + obj.f(202); + obj.f(203); + obj.f(204); + obj.f(205); + obj.f(206); + obj.f(207); + obj.f(208); + obj.f(209); + obj.f(210); + obj.f(211); + obj.f(212); + obj.f(213); + obj.f(214); + obj.f(215); + obj.f(216); + obj.f(217); + obj.f(218); + obj.f(219); + obj.f(220); + obj.f(221); + obj.f(222); + obj.f(223); + obj.f(224); + obj.f(225); + obj.f(226); + obj.f(227); + obj.f(228); + obj.f(229); + obj.f(230); + obj.f(231); + obj.f(232); + obj.f(233); + obj.f(234); + obj.f(235); + obj.f(236); + obj.f(237); + obj.f(238); + obj.f(239); + obj.f(240); + obj.f(241); + obj.f(242); + obj.f(243); + obj.f(244); + obj.f(245); + obj.f(246); + obj.f(247); + obj.f(248); + obj.f(249); + obj.f(250); + obj.f(251); + obj.f(252); + obj.f(253); + obj.f(254); + obj.f(255); + debugger; + obj.f(256); + obj.f(257); + obj.f(258); + obj.f(259); +} + +let break_count = 0; + +function listener(event, exec_state, event_data, data) { + if (event != debug.Debug.DebugEvent.Break) return; + try { + exec_state.prepareStep(debug.Debug.StepAction.StepNext); + break_count++; + } catch { + %AbortJS("unexpected exception"); + } +} + +debug.Debug.setListener(listener); +foo(); +debug.Debug.setListener(null); +assertEquals(7, break_count);
diff --git a/src/v8/test/debugger/regress/regress-crbug-840288.js b/src/v8/test/debugger/regress/regress-crbug-840288.js new file mode 100644 index 0000000..ff08fd9 --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-840288.js
@@ -0,0 +1,24 @@ +// Copyright 2018 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. + +load("test/mjsunit/wasm/wasm-module-builder.js"); + +Debug = debug.Debug + +function listener(event, exec_state, event_data, data) { + if (event == Debug.DebugEvent.AfterCompile) { + // The actual source doesn't matter, just don't crash. + assertEquals("func $main\nend\n", event_data.script().source()); + } +}; + +// Add the debug event listener. +Debug.setListener(listener); + +var builder = new WasmModuleBuilder(); +builder.addFunction('main', kSig_v_v).addBody([]).exportFunc(); +var promise = WebAssembly.compile(builder.toBuffer()); + +// Clear the debug listener only after the event fired. +promise.then(() => Debug.setListener(null), assertUnreachable);
diff --git a/src/v8/test/debugger/regress/regress-crbug-882664.js b/src/v8/test/debugger/regress/regress-crbug-882664.js new file mode 100644 index 0000000..399cfba --- /dev/null +++ b/src/v8/test/debugger/regress/regress-crbug-882664.js
@@ -0,0 +1,41 @@ +// Copyright 2018 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. + +function provoke_scaling_prefix() { + var a = [0]; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; a[0]++; + return a; +} + +Debug = debug.Debug; + +function success(expectation, source) { + const result = Debug.evaluateGlobal(source, true).value(); + assertEquals(expectation, result); +} + +success([216], "provoke_scaling_prefix()");
diff --git a/src/v8/test/debugger/test-api.js b/src/v8/test/debugger/test-api.js index 0e9670b..511fb33 100644 --- a/src/v8/test/debugger/test-api.js +++ b/src/v8/test/debugger/test-api.js
@@ -41,14 +41,6 @@ StepIn: 2, }; - // The different types of scripts matching enum ScriptType in objects.h. - this.ScriptType = { Native: 0, - Extension: 1, - Normal: 2, - Wasm: 3, - Inspector: 4, - }; - // A copy of the scope types from runtime-debug.cc. // NOTE: these constants should be backward-compatible, so // add new ones to the end of this list. @@ -67,11 +59,6 @@ this.ExceptionBreak = { Caught : 0, Uncaught: 1 }; - // The different script break point types. - this.ScriptBreakPointType = { ScriptId: 0, - ScriptName: 1, - ScriptRegExp: 2 }; - // Store the current script id so we can skip corresponding break events. this.thisScriptId = %FunctionGetScriptId(receive); @@ -139,23 +126,6 @@ return this.setBreakPointAtLocation(scriptid, loc, opt_condition); } - setScriptBreakPoint(type, scriptid, opt_line, opt_column, opt_condition) { - // Only sets by script id are supported for now. - assertEquals(this.ScriptBreakPointType.ScriptId, type); - return this.setScriptBreakPointById(scriptid, opt_line, opt_column, - opt_condition); - } - - setScriptBreakPointById(scriptid, opt_line, opt_column, opt_condition) { - const loc = %ScriptLocationFromLine2(scriptid, opt_line, opt_column, 0); - return this.setBreakPointAtLocation(scriptid, loc, opt_condition); - } - - setBreakPointByScriptIdAndPosition(scriptid, position) { - const loc = %ScriptPositionInfo2(scriptid, position, false); - return this.setBreakPointAtLocation(scriptid, loc, undefined); - } - clearBreakPoint(breakpoint) { assertTrue(this.breakpoints.has(breakpoint)); const breakid = breakpoint.id; @@ -207,71 +177,12 @@ }; } - scripts() { - // Collect all scripts in the heap. - return %DebugGetLoadedScripts(); - } - - // Returns a Script object. If the parameter is a function the return value - // is the script in which the function is defined. If the parameter is a - // string the return value is the script for which the script name has that - // string value. If it is a regexp and there is a unique script whose name - // matches we return that, otherwise undefined. - findScript(func_or_script_name) { - if (%IsFunction(func_or_script_name)) { - return %FunctionGetScript(func_or_script_name); - } else if (%IsRegExp(func_or_script_name)) { - var scripts = this.scripts(); - var last_result = null; - var result_count = 0; - for (var i in scripts) { - var script = scripts[i]; - if (func_or_script_name.test(script.name)) { - last_result = script; - result_count++; - } - } - // Return the unique script matching the regexp. If there are more - // than one we don't return a value since there is no good way to - // decide which one to return. Returning a "random" one, say the - // first, would introduce nondeterminism (or something close to it) - // because the order is the heap iteration order. - if (result_count == 1) { - return last_result; - } else { - return undefined; - } - } else { - return %GetScript(func_or_script_name); - } - } - - // Returns the script source. If the parameter is a function the return value - // is the script source for the script in which the function is defined. If the - // parameter is a string the return value is the script for which the script - // name has that string value. - scriptSource(func_or_script_name) { - return this.findScript(func_or_script_name).source; + // Returns the script source. The return value is the script source for the + // script in which the function is defined. + scriptSource(func) { + return %FunctionGetScriptSource(func); }; - sourcePosition(f) { - if (!%IsFunction(f)) throw new Error("Not passed a Function"); - return %FunctionGetScriptSourcePosition(f); - }; - - // Returns the character position in a script based on a line number and an - // optional position within that line. - findScriptSourcePosition(script, opt_line, opt_column) { - var location = %ScriptLocationFromLine(script, opt_line, opt_column, 0); - return location ? location.position : null; - }; - - findFunctionSourceLocation(func, opt_line, opt_column) { - var script = %FunctionGetScript(func); - var script_offset = %FunctionGetScriptSourcePosition(func); - return %ScriptLocationFromLine(script, opt_line, opt_column, script_offset); - } - setBreakPointsActive(enabled) { const {msgid, msg} = this.createMessage( "Debugger.setBreakpointsActive", { active : enabled }); @@ -296,8 +207,8 @@ } function setScopeVariableValue(name, value) { - const res = %SetScopeVariableValue(gen, null, null, index, name, value); - if (!res) throw new Error("Failed to set variable value"); + const res = %SetGeneratorScopeVariableValue(gen, index, name, value); + if (!res) throw new Error("Failed to set variable '" + name + "' value"); } const scopeObject = @@ -323,11 +234,6 @@ return scopes; } - get LiveEdit() { - const debugContext = %GetDebugContext(); - return debugContext.Debug.LiveEdit; - } - // --- Internal methods. ----------------------------------------------------- getNextMessageId() { @@ -392,13 +298,7 @@ const breakid = result.breakpointId; assertTrue(breakid !== undefined); - const actualLoc = %ScriptLocationFromLine2(scriptid, - result.actualLocation.lineNumber, result.actualLocation.columnNumber, - 0); - - const breakpoint = { id : result.breakpointId, - actual_position : actualLoc.position, - } + const breakpoint = { id : result.breakpointId } this.breakpoints.add(breakpoint); return breakpoint; @@ -462,27 +362,6 @@ }; } - execStateScopeDetails(scope) { - var start_position; - var end_position - const start = scope.startLocation; - const end = scope.endLocation; - if (start) { - start_position = %ScriptLocationFromLine2( - parseInt(start.scriptId), start.lineNumber, start.columnNumber, 0) - .position; - } - if (end) { - end_position = %ScriptLocationFromLine2( - parseInt(end.scriptId), end.lineNumber, end.columnNumber, 0) - .position; - } - return { name : () => scope.name, - startPosition : () => start_position, - endPosition : () => end_position - }; - } - setVariableValue(frame, scope_index, name, value) { const frameid = frame.callFrameId; const {msgid, msg} = this.createMessage( @@ -495,7 +374,7 @@ this.sendMessage(msg); const reply = this.takeReplyChecked(msgid); if (reply.error) { - throw new Error("Failed to set variable value"); + throw new Error("Failed to set variable '" + name + "' value"); } } @@ -508,7 +387,6 @@ setVariableValue : (name, value) => this.setVariableValue(frame, scope_index, name, value), - details : () => this.execStateScopeDetails(scope) }; } @@ -653,10 +531,19 @@ } break; } + case "bigint": { + assertEquals("n", obj.unserializableValue.charAt( + obj.unserializableValue.length - 1)); + value = eval(obj.unserializableValue); + break; + } case "string": case "boolean": { break; } + case "function": { + value = obj.description; + } default: { break; } @@ -737,9 +624,9 @@ }; } - execStateEvaluateGlobal(expr) { + evaluateGlobal(expr, throw_on_side_effect) { const {msgid, msg} = this.createMessage( - "Runtime.evaluate", { expression : expr }); + "Runtime.evaluate", { expression : expr, throwOnSideEffect: throw_on_side_effect }); this.sendMessage(msg); const reply = this.takeReplyChecked(msgid); @@ -836,7 +723,7 @@ let execState = { frames : params.callFrames, prepareStep : this.execStatePrepareStep.bind(this), evaluateGlobal : - (expr) => this.execStateEvaluateGlobal(expr), + (expr) => this.evaluateGlobal(expr), frame : (index) => this.execStateFrame( index ? params.callFrames[index] : params.callFrames[0]),
diff --git a/src/v8/test/debugger/testcfg.py b/src/v8/test/debugger/testcfg.py index e287077..74d885b 100644 --- a/src/v8/test/debugger/testcfg.py +++ b/src/v8/test/debugger/testcfg.py
@@ -9,30 +9,23 @@ from testrunner.objects import testcase FILES_PATTERN = re.compile(r"//\s+Files:(.*)") -MODULE_PATTERN = re.compile(r"^// MODULE$", flags=re.MULTILINE) + + +class TestLoader(testsuite.JSTestLoader): + @property + def excluded_files(self): + return {"test-api.js"} + class TestSuite(testsuite.TestSuite): - def ListTests(self, context): - tests = [] - for dirname, dirs, files in os.walk(self.root): - for dotted in [x for x in dirs if x.startswith('.')]: - dirs.remove(dotted) - dirs.sort() - files.sort() - for filename in files: - if (filename.endswith(".js") and filename != "test-api.js"): - fullpath = os.path.join(dirname, filename) - relpath = fullpath[len(self.root) + 1 : -3] - testname = relpath.replace(os.path.sep, "/") - test = self._create_test(testname) - tests.append(test) - return tests + def _test_loader_class(self): + return TestLoader def _test_class(self): return TestCase -class TestCase(testcase.TestCase): +class TestCase(testcase.D8TestCase): def __init__(self, *args, **kwargs): super(TestCase, self).__init__(*args, **kwargs) @@ -57,26 +50,30 @@ files.append(os.path.join(self.suite.root, "test-api.js")) files.extend([os.path.normpath(os.path.join(self.suite.root, '..', '..', f)) for f in files_list]) - if MODULE_PATTERN.search(source): - files.append("--module") - files.append(os.path.join(self.suite.root, self.path + self._get_suffix())) + files.append(self._get_source_path()) return files - def _get_files_params(self, ctx): + def _get_files_params(self): files = self._source_files - if ctx.isolates: + if self._test_config.isolates: files = files + ['--isolate'] + files return files def _get_source_flags(self): return self._source_flags - def _get_suite_flags(self, ctx): + def _get_suite_flags(self): return ['--enable-inspector', '--allow-natives-syntax'] def _get_source_path(self): - return os.path.join(self.suite.root, self.path + self._get_suffix()) + base_path = os.path.join(self.suite.root, self.path) + # Try .js first, and fall back to .mjs. + # TODO(v8:9406): clean this up by never separating the path from + # the extension in the first place. + if os.path.exists(base_path + self._get_suffix()): + return base_path + self._get_suffix() + return base_path + '.mjs' -def GetSuite(name, root): - return TestSuite(name, root) +def GetSuite(*args, **kwargs): + return TestSuite(*args, **kwargs)