v8/test/debugger/debug/debug-scopes-suspended-generators.js
jgruber cda1a60ab3 [debug-wrapper] Migrate suspended generator scope test
Unfortunately, there's currently no satisfying way of accessing scopes
of suspended generator objects through inspector. This CL implements
access to such scopes through runtime functions instead.

BUG=v8:5530

Review-Url: https://codereview.chromium.org/2513343004
Cr-Commit-Position: refs/heads/master@{#41179}
2016-11-22 13:32:13 +00:00

459 lines
11 KiB
JavaScript

// 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: --ignition
// The functions used for testing backtraces. They are at the top to make the
// testing of source line/column easier.
var Debug = debug.Debug;
var test_name;
var exception;
var begin_test_count = 0;
var end_test_count = 0;
// Initialize for a new test.
function BeginTest(name) {
test_name = name;
exception = null;
begin_test_count++;
}
// Check result of a test.
function EndTest() {
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.scopeIndex(), scope2.scopeIndex());
assertPropertiesEqual(scope1.scopeObject().value(),
scope2.scopeObject().value());
}
// Check that the scope chain contains the expected types of scopes.
function CheckScopeChain(scopes, gen) {
var all_scopes = Debug.generatorScopes(gen);
assertEquals(scopes.length, Debug.generatorScopeCount(gen));
assertEquals(scopes.length, all_scopes.length,
"FrameMirror.allScopes length");
for (var i = 0; i < scopes.length; i++) {
var scope = all_scopes[i];
assertEquals(scopes[i], scope.scopeType(),
`Scope ${i} has unexpected type`);
// Check the global object when hitting the global scope.
if (scopes[i] == debug.ScopeType.Global) {
// Objects don't have same class (one is "global", other is "Object",
// so just check the properties directly.
assertPropertiesEqual(this, scope.scopeObject().value());
}
}
}
// Check that the content of the scope is as expected. For functions just check
// that there is a function.
function CheckScopeContent(content, number, gen) {
var scope = Debug.generatorScope(gen, number);
var count = 0;
for (var p in content) {
var property_mirror = scope.scopeObject().property(p);
if (content[p] === undefined) {
assertTrue(property_mirror === undefined);
} else {
assertFalse(property_mirror === undefined,
'property ' + p + ' not found in scope');
}
if (typeof(content[p]) === 'function') {
assertTrue(typeof property_mirror == "function");
} else {
assertEquals(content[p], property_mirror,
'property ' + p + ' has unexpected value');
}
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') !== undefined) {
scope_size--;
}
// Ditto for 'this'.
if (scope.scopeObject().property('this') !== undefined) {
scope_size--;
}
// Temporary variables introduced by the parser have not been materialized.
assertTrue(scope.scopeObject().property('') === undefined);
if (count != scope_size) {
print('Names found in scope:');
var names = scope.scopeObject().propertyNames();
for (var i = 0; i < names.length; i++) {
print(names[i]);
}
}
assertEquals(count, scope_size);
}
// Simple empty closure scope.
function *gen1() {
yield 1;
return 2;
}
var g = gen1();
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({}, 0, g);
// Closure scope with a parameter.
function *gen2(a) {
yield a;
return 2;
}
g = gen2(42);
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 42}, 0, g);
// Closure scope with a parameter.
function *gen3(a) {
var b = 1
yield a;
return b;
}
g = gen3(0);
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 0, b: undefined}, 0, g);
g.next(); // Create b.
CheckScopeContent({a: 0, b: 1}, 0, g);
// Closure scope with a parameter.
function *gen4(a, b) {
var x = 2;
yield a;
var y = 3;
return b;
}
g = gen4(0, 1);
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 0, b: 1, x: undefined, y: undefined}, 0, g);
g.next(); // Create x.
CheckScopeContent({a: 0, b: 1, x: 2, y: undefined}, 0, g);
g.next(); // Create y.
CheckScopeContent({a: 0, b: 1, x: 2, y: 3}, 0, g);
// Closure introducing local variable using eval.
function *gen5(a) {
eval('var b = 2');
return b;
}
g = gen5(1);
g.next();
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 1, b: 2}, 0, g);
// Single empty with block.
function *gen6() {
with({}) {
yield 1;
}
yield 2;
return 3;
}
g = gen6();
g.next();
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({}, 0, g);
g.next();
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
// Nested empty with blocks.
function *gen7() {
with({}) {
with({}) {
yield 1;
}
yield 2;
}
return 3;
}
g = gen7();
g.next();
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({}, 0, g);
// Nested with blocks using in-place object literals.
function *gen8() {
with({a: 1,b: 2}) {
with({a: 2,b: 1}) {
yield a;
}
yield a;
}
return 3;
}
g = gen8();
g.next();
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 2, b: 1}, 0, g);
g.next();
CheckScopeContent({a: 1, b: 2}, 0, g);
// Catch block.
function *gen9() {
try {
throw 42;
} catch (e) {
yield e;
}
return 3;
}
g = gen9();
g.next();
CheckScopeChain([debug.ScopeType.Catch,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({e: 42}, 0, g);
// For statement with block scope.
function *gen10() {
for (let i = 0; i < 42; i++) yield i;
return 3;
}
g = gen10();
g.next();
CheckScopeChain([debug.ScopeType.Block,
debug.ScopeType.Block,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({i: 0}, 0, g);
g.next();
CheckScopeContent({i: 1}, 0, g);
CheckScopeContent({i: 0}, 1, g); // Additional block scope with i = 0;
// Nested generators.
var gen12;
function *gen11() {
gen12 = function*() {
var a = 1;
yield 1;
return 2;
}();
var a = 0;
yield* gen12;
}
gen11().next();
g = gen12;
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 1}, 0, g);
CheckScopeContent({a: 0}, 1, g);
// Set a variable in an empty scope.
function *gen13() {
yield 1;
return 2;
}
var g = gen13();
assertThrows(() => Debug.generatorScope(g, 0).setVariableValue("a", 42));
CheckScopeContent({}, 0, g);
// Set a variable in a simple scope.
function *gen14() {
var a = 0;
yield 1;
yield a;
return 2;
}
var g = gen14();
assertEquals(1, g.next().value);
CheckScopeContent({a: 0}, 0, g);
Debug.generatorScope(g, 0).setVariableValue("a", 1);
CheckScopeContent({a: 1}, 0, g);
assertEquals(1, g.next().value);
// Set a variable in nested with blocks using in-place object literals.
function *gen15() {
var c = 3;
with({a: 1,b: 2}) {
var d = 4;
yield a;
var e = 5;
}
yield e;
return e;
}
var g = gen15();
assertEquals(1, g.next().value);
CheckScopeChain([debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({a: 1, b: 2}, 0, g);
CheckScopeContent({c: 3, d: 4, e: undefined}, 1, g);
// Variables don't exist in given scope.
assertThrows(() => Debug.generatorScope(g, 0).setVariableValue("c", 42));
assertThrows(() => Debug.generatorScope(g, 1).setVariableValue("a", 42));
// Variables in with scope are immutable.
assertThrows(() => Debug.generatorScope(g, 0).setVariableValue("a", 3));
assertThrows(() => Debug.generatorScope(g, 0).setVariableValue("b", 3));
Debug.generatorScope(g, 1).setVariableValue("c", 1);
Debug.generatorScope(g, 1).setVariableValue("e", 42);
CheckScopeContent({a: 1, b: 2}, 0, g);
CheckScopeContent({c: 1, d: 4, e: 42}, 1, g);
assertEquals(5, g.next().value); // Initialized after set.
CheckScopeChain([debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
Debug.generatorScope(g, 0).setVariableValue("e", 42);
CheckScopeContent({c: 1, d: 4, e: 42}, 0, g);
assertEquals(42, g.next().value);
// Set a variable in nested with blocks using in-place object literals plus a
// nested block scope.
function *gen16() {
var c = 3;
with({a: 1,b: 2}) {
let d = 4;
yield a;
let e = 5;
yield d;
}
return 3;
}
var g = gen16();
g.next();
CheckScopeChain([debug.ScopeType.Block,
debug.ScopeType.With,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({d: 4}, 0, g);
CheckScopeContent({a: 1, b: 2}, 1, g);
CheckScopeContent({c: 3}, 2, g);
Debug.generatorScope(g, 0).setVariableValue("d", 1);
CheckScopeContent({d: 1}, 0, g);
assertEquals(1, g.next().value);
// Set variable in catch block.
var yyzyzzyz = 4829;
let xxxyyxxyx = 42284;
function *gen17() {
try {
throw 42;
} catch (e) {
yield e;
yield e;
}
return 3;
}
g = gen17();
g.next();
CheckScopeChain([debug.ScopeType.Catch,
debug.ScopeType.Closure,
debug.ScopeType.Script,
debug.ScopeType.Global], g);
CheckScopeContent({e: 42}, 0, g);
CheckScopeContent({xxxyyxxyx: 42284,
printProtocolMessages : printProtocolMessages,
activeWrapper : activeWrapper,
DebugWrapper : DebugWrapper
}, 2, g);
Debug.generatorScope(g, 0).setVariableValue("e", 1);
CheckScopeContent({e: 1}, 0, g);
assertEquals(1, g.next().value);
// Script scope.
Debug.generatorScope(g, 2).setVariableValue("xxxyyxxyx", 42);
assertEquals(42, xxxyyxxyx);
// Global scope.
assertThrows(() => Debug.generatorScope(g, 3).setVariableValue("yyzyzzyz", 42));
assertEquals(4829, yyzyzzyz);