Issue 2081: Expose function's (closure's) inner context in debugger.
This is against the correct branch (bleeding_edge). Review URL: https://chromiumcodereview.appspot.com/10171003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11458 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
94e5a8dfcd
commit
569eba39f5
@ -1957,7 +1957,7 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
|
||||
if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
|
||||
frame_index = request.arguments.frameNumber;
|
||||
if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
|
||||
return response.failed('Invalid frame number');
|
||||
throw new Error('Invalid frame number');
|
||||
}
|
||||
return this.exec_state_.frame(frame_index);
|
||||
} else {
|
||||
@ -1966,20 +1966,44 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
|
||||
};
|
||||
|
||||
|
||||
DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
|
||||
// No frames no scopes.
|
||||
if (this.exec_state_.frameCount() == 0) {
|
||||
return response.failed('No scopes');
|
||||
// Gets scope host object from request. It is either a function
|
||||
// ('functionHandle' argument must be specified) or a stack frame
|
||||
// ('frameNumber' may be specified and the current frame is taken by default).
|
||||
DebugCommandProcessor.prototype.scopeHolderForScopeRequest_ =
|
||||
function(request) {
|
||||
if (request.arguments && "functionHandle" in request.arguments) {
|
||||
if (!IS_NUMBER(request.arguments.functionHandle)) {
|
||||
throw new Error('Function handle must be a number');
|
||||
}
|
||||
var function_mirror = LookupMirror(request.arguments.functionHandle);
|
||||
if (!function_mirror) {
|
||||
throw new Error('Failed to find function object by handle');
|
||||
}
|
||||
if (!function_mirror.isFunction()) {
|
||||
throw new Error('Value of non-function type is found by handle');
|
||||
}
|
||||
return function_mirror;
|
||||
} else {
|
||||
// No frames no scopes.
|
||||
if (this.exec_state_.frameCount() == 0) {
|
||||
throw new Error('No scopes');
|
||||
}
|
||||
|
||||
// Get the frame for which the scopes are requested.
|
||||
var frame = this.frameForScopeRequest_(request);
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the frame for which the scopes are requested.
|
||||
var frame = this.frameForScopeRequest_(request);
|
||||
|
||||
// Fill all scopes for this frame.
|
||||
var total_scopes = frame.scopeCount();
|
||||
DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
|
||||
var scope_holder = this.scopeHolderForScopeRequest_(request);
|
||||
|
||||
// Fill all scopes for this frame or function.
|
||||
var total_scopes = scope_holder.scopeCount();
|
||||
var scopes = [];
|
||||
for (var i = 0; i < total_scopes; i++) {
|
||||
scopes.push(frame.scope(i));
|
||||
scopes.push(scope_holder.scope(i));
|
||||
}
|
||||
response.body = {
|
||||
fromScope: 0,
|
||||
@ -1991,24 +2015,19 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
|
||||
|
||||
|
||||
DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
|
||||
// No frames no scopes.
|
||||
if (this.exec_state_.frameCount() == 0) {
|
||||
return response.failed('No scopes');
|
||||
}
|
||||
|
||||
// Get the frame for which the scope is requested.
|
||||
var frame = this.frameForScopeRequest_(request);
|
||||
// Get the frame or function for which the scope is requested.
|
||||
var scope_holder = this.scopeHolderForScopeRequest_(request);
|
||||
|
||||
// With no scope argument just return top scope.
|
||||
var scope_index = 0;
|
||||
if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
|
||||
scope_index = %ToNumber(request.arguments.number);
|
||||
if (scope_index < 0 || frame.scopeCount() <= scope_index) {
|
||||
if (scope_index < 0 || scope_holder.scopeCount() <= scope_index) {
|
||||
return response.failed('Invalid scope number');
|
||||
}
|
||||
}
|
||||
|
||||
response.body = frame.scope(scope_index);
|
||||
response.body = scope_holder.scope(scope_index);
|
||||
};
|
||||
|
||||
|
||||
|
@ -913,6 +913,22 @@ FunctionMirror.prototype.constructedBy = function(opt_max_instances) {
|
||||
};
|
||||
|
||||
|
||||
FunctionMirror.prototype.scopeCount = function() {
|
||||
if (this.resolved()) {
|
||||
return %GetFunctionScopeCount(this.value());
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FunctionMirror.prototype.scope = function(index) {
|
||||
if (this.resolved()) {
|
||||
return new ScopeMirror(void 0, this, index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FunctionMirror.prototype.toText = function() {
|
||||
return this.source();
|
||||
};
|
||||
@ -1589,7 +1605,7 @@ FrameMirror.prototype.scopeCount = function() {
|
||||
|
||||
|
||||
FrameMirror.prototype.scope = function(index) {
|
||||
return new ScopeMirror(this, index);
|
||||
return new ScopeMirror(this, void 0, index);
|
||||
};
|
||||
|
||||
|
||||
@ -1752,39 +1768,54 @@ FrameMirror.prototype.toText = function(opt_locals) {
|
||||
var kScopeDetailsTypeIndex = 0;
|
||||
var kScopeDetailsObjectIndex = 1;
|
||||
|
||||
function ScopeDetails(frame, index) {
|
||||
this.break_id_ = frame.break_id_;
|
||||
this.details_ = %GetScopeDetails(frame.break_id_,
|
||||
frame.details_.frameId(),
|
||||
frame.details_.inlinedFrameIndex(),
|
||||
index);
|
||||
function ScopeDetails(frame, fun, index) {
|
||||
if (frame) {
|
||||
this.break_id_ = frame.break_id_;
|
||||
this.details_ = %GetScopeDetails(frame.break_id_,
|
||||
frame.details_.frameId(),
|
||||
frame.details_.inlinedFrameIndex(),
|
||||
index);
|
||||
} else {
|
||||
this.details_ = %GetFunctionScopeDetails(fun.value(), index);
|
||||
this.break_id_ = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ScopeDetails.prototype.type = function() {
|
||||
%CheckExecutionState(this.break_id_);
|
||||
if (!IS_UNDEFINED(this.break_id_)) {
|
||||
%CheckExecutionState(this.break_id_);
|
||||
}
|
||||
return this.details_[kScopeDetailsTypeIndex];
|
||||
};
|
||||
|
||||
|
||||
ScopeDetails.prototype.object = function() {
|
||||
%CheckExecutionState(this.break_id_);
|
||||
if (!IS_UNDEFINED(this.break_id_)) {
|
||||
%CheckExecutionState(this.break_id_);
|
||||
}
|
||||
return this.details_[kScopeDetailsObjectIndex];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mirror object for scope.
|
||||
* Mirror object for scope of frame or function. Either frame or function must
|
||||
* be specified.
|
||||
* @param {FrameMirror} frame The frame this scope is a part of
|
||||
* @param {FunctionMirror} function The function this scope is a part of
|
||||
* @param {number} index The scope index in the frame
|
||||
* @constructor
|
||||
* @extends Mirror
|
||||
*/
|
||||
function ScopeMirror(frame, index) {
|
||||
function ScopeMirror(frame, function, index) {
|
||||
%_CallFunction(this, SCOPE_TYPE, Mirror);
|
||||
this.frame_index_ = frame.index_;
|
||||
if (frame) {
|
||||
this.frame_index_ = frame.index_;
|
||||
} else {
|
||||
this.frame_index_ = undefined;
|
||||
}
|
||||
this.scope_index_ = index;
|
||||
this.details_ = new ScopeDetails(frame, index);
|
||||
this.details_ = new ScopeDetails(frame, function, index);
|
||||
}
|
||||
inherits(ScopeMirror, Mirror);
|
||||
|
||||
@ -2281,6 +2312,15 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
|
||||
|
||||
serializeLocationFields(mirror.sourceLocation(), content);
|
||||
}
|
||||
|
||||
content.scopes = [];
|
||||
for (var i = 0; i < mirror.scopeCount(); i++) {
|
||||
var scope = mirror.scope(i);
|
||||
content.scopes.push({
|
||||
type: scope.scopeType(),
|
||||
index: i
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add date specific properties.
|
||||
|
@ -11018,10 +11018,10 @@ static Handle<JSObject> MaterializeModuleScope(
|
||||
}
|
||||
|
||||
|
||||
// Iterate over the actual scopes visible from a stack frame. The iteration
|
||||
// proceeds from the innermost visible nested scope outwards. All scopes are
|
||||
// backed by an actual context except the local scope, which is inserted
|
||||
// "artificially" in the context chain.
|
||||
// Iterate over the actual scopes visible from a stack frame or from a closure.
|
||||
// The iteration proceeds from the innermost visible nested scope outwards.
|
||||
// All scopes are backed by an actual context except the local scope,
|
||||
// which is inserted "artificially" in the context chain.
|
||||
class ScopeIterator {
|
||||
public:
|
||||
enum ScopeType {
|
||||
@ -11122,6 +11122,18 @@ class ScopeIterator {
|
||||
}
|
||||
}
|
||||
|
||||
ScopeIterator(Isolate* isolate,
|
||||
Handle<JSFunction> function)
|
||||
: isolate_(isolate),
|
||||
frame_(NULL),
|
||||
inlined_jsframe_index_(0),
|
||||
function_(function),
|
||||
context_(function->context()) {
|
||||
if (function->IsBuiltin()) {
|
||||
context_ = Handle<Context>();
|
||||
}
|
||||
}
|
||||
|
||||
// More scopes?
|
||||
bool Done() { return context_.is_null(); }
|
||||
|
||||
@ -11342,6 +11354,22 @@ static const int kScopeDetailsTypeIndex = 0;
|
||||
static const int kScopeDetailsObjectIndex = 1;
|
||||
static const int kScopeDetailsSize = 2;
|
||||
|
||||
|
||||
static MaybeObject* MaterializeScopeDetails(Isolate* isolate,
|
||||
ScopeIterator* it) {
|
||||
// Calculate the size of the result.
|
||||
int details_size = kScopeDetailsSize;
|
||||
Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
|
||||
|
||||
// Fill in scope details.
|
||||
details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
|
||||
Handle<JSObject> scope_object = it->ScopeObject();
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
|
||||
details->set(kScopeDetailsObjectIndex, *scope_object);
|
||||
|
||||
return *isolate->factory()->NewJSArrayWithElements(details);
|
||||
}
|
||||
|
||||
// Return an array with scope details
|
||||
// args[0]: number: break id
|
||||
// args[1]: number: frame index
|
||||
@ -11379,18 +11407,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
|
||||
if (it.Done()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
return MaterializeScopeDetails(isolate, &it);
|
||||
}
|
||||
|
||||
// Calculate the size of the result.
|
||||
int details_size = kScopeDetailsSize;
|
||||
Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
|
||||
|
||||
// Fill in scope details.
|
||||
details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
|
||||
Handle<JSObject> scope_object = it.ScopeObject();
|
||||
RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
|
||||
details->set(kScopeDetailsObjectIndex, *scope_object);
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
|
||||
return *isolate->factory()->NewJSArrayWithElements(details);
|
||||
// Check arguments.
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
||||
|
||||
// Count the visible scopes.
|
||||
int n = 0;
|
||||
for (ScopeIterator it(isolate, fun); !it.Done(); it.Next()) {
|
||||
n++;
|
||||
}
|
||||
|
||||
return Smi::FromInt(n);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeDetails) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 2);
|
||||
|
||||
// Check arguments.
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
|
||||
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
|
||||
|
||||
// Find the requested scope.
|
||||
int n = 0;
|
||||
ScopeIterator it(isolate, fun);
|
||||
for (; !it.Done() && n < index; it.Next()) {
|
||||
n++;
|
||||
}
|
||||
if (it.Done()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
return MaterializeScopeDetails(isolate, &it);
|
||||
}
|
||||
|
||||
|
||||
|
@ -404,6 +404,8 @@ namespace internal {
|
||||
F(GetFrameDetails, 2, 1) \
|
||||
F(GetScopeCount, 2, 1) \
|
||||
F(GetScopeDetails, 4, 1) \
|
||||
F(GetFunctionScopeCount, 1, 1) \
|
||||
F(GetFunctionScopeDetails, 2, 1) \
|
||||
F(DebugPrintScopes, 0, 1) \
|
||||
F(GetThreadCount, 1, 1) \
|
||||
F(GetThreadDetails, 2, 1) \
|
||||
|
162
test/mjsunit/debug-function-scopes.js
Normal file
162
test/mjsunit/debug-function-scopes.js
Normal file
@ -0,0 +1,162 @@
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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: --expose-debug-as debug
|
||||
|
||||
// Get the Debug object exposed from the debug context global object.
|
||||
var Debug = debug.Debug;
|
||||
|
||||
function CheckScope(scope_mirror, scope_expectations, expected_scope_type) {
|
||||
assertEquals(expected_scope_type, scope_mirror.scopeType());
|
||||
|
||||
var scope_object = scope_mirror.scopeObject().value();
|
||||
|
||||
for (var name in scope_expectations) {
|
||||
var actual = scope_object[name];
|
||||
var expected = scope_expectations[name];
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
// A copy of the scope types from mirror-debugger.js.
|
||||
var ScopeType = { Global: 0,
|
||||
Local: 1,
|
||||
With: 2,
|
||||
Closure: 3,
|
||||
Catch: 4,
|
||||
Block: 5 };
|
||||
|
||||
var f1 = (function F1(x) {
|
||||
function F2(y) {
|
||||
var z = x + y;
|
||||
with ({w: 5, v: "Capybara"}) {
|
||||
var F3 = function(a, b) {
|
||||
function F4(p) {
|
||||
return p + a + b + z + w + v.length;
|
||||
}
|
||||
return F4;
|
||||
}
|
||||
return F3(4, 5);
|
||||
}
|
||||
}
|
||||
return F2(17);
|
||||
})(5);
|
||||
|
||||
var mirror = Debug.MakeMirror(f1);
|
||||
|
||||
assertEquals(5, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(1), { w: 5, v: "Capybara" }, ScopeType.With);
|
||||
CheckScope(mirror.scope(2), { y: 17, z: 22 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(3), { x: 5 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(4), {}, ScopeType.Global);
|
||||
|
||||
var f2 = function() { return 5; }
|
||||
|
||||
var mirror = Debug.MakeMirror(f2);
|
||||
|
||||
assertEquals(1, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), {}, ScopeType.Global);
|
||||
|
||||
var f3 = (function F1(invisible_parameter) {
|
||||
var invisible1 = 1;
|
||||
var visible1 = 10;
|
||||
return (function F2() {
|
||||
var invisible2 = 2;
|
||||
return (function F3() {
|
||||
var visible2 = 20;
|
||||
var invisible2 = 3;
|
||||
return (function () {return visible1 + visible2 + visible1a;});
|
||||
})();
|
||||
})();
|
||||
})(5);
|
||||
|
||||
var mirror = Debug.MakeMirror(f3);
|
||||
|
||||
assertEquals(3, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), { visible2: 20 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(1), { visible1: 10 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(2), {}, ScopeType.Global);
|
||||
|
||||
|
||||
var f4 = (function One() {
|
||||
try {
|
||||
throw "I'm error 1";
|
||||
} catch (e1) {
|
||||
try {
|
||||
throw "I'm error 2";
|
||||
} catch (e2) {
|
||||
return function GetError() {
|
||||
return e1 + e2;
|
||||
};
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
var mirror = Debug.MakeMirror(f4);
|
||||
|
||||
assertEquals(3, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), { e2: "I'm error 2" }, ScopeType.Catch);
|
||||
CheckScope(mirror.scope(1), { e1: "I'm error 1" }, ScopeType.Catch);
|
||||
CheckScope(mirror.scope(2), {}, ScopeType.Global);
|
||||
|
||||
|
||||
var f5 = (function Raz(p1, p2) {
|
||||
var p3 = p1 + p2;
|
||||
return (function() {
|
||||
var p4 = 20;
|
||||
var p5 = 21;
|
||||
var p6 = 22;
|
||||
return eval("(function(p7){return p1 + p4 + p6 + p7})");
|
||||
})();
|
||||
})(1,2);
|
||||
|
||||
var mirror = Debug.MakeMirror(f5);
|
||||
|
||||
assertEquals(3, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), { p4: 20, p6: 22 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(1), { p1: 1 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(2), {}, ScopeType.Global);
|
||||
|
||||
|
||||
function CheckNoScopeVisible(f) {
|
||||
var mirror = Debug.MakeMirror(f);
|
||||
assertEquals(0, mirror.scopeCount());
|
||||
}
|
||||
|
||||
CheckNoScopeVisible(Number);
|
||||
|
||||
CheckNoScopeVisible(Function.toString);
|
||||
|
||||
// This getter is known to be implemented as closure.
|
||||
CheckNoScopeVisible(new Error().__lookupGetter__("stack"));
|
||||
|
115
test/mjsunit/harmony/debug-function-scopes.js
Normal file
115
test/mjsunit/harmony/debug-function-scopes.js
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright 2012 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (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: --expose-debug-as debug --harmony-scoping
|
||||
|
||||
"use strict";
|
||||
|
||||
// Get the Debug object exposed from the debug context global object.
|
||||
var Debug = debug.Debug;
|
||||
|
||||
function CheckScope(scope_mirror, scope_expectations, expected_scope_type) {
|
||||
assertEquals(expected_scope_type, scope_mirror.scopeType());
|
||||
|
||||
var scope_object = scope_mirror.scopeObject().value();
|
||||
|
||||
for (let name in scope_expectations) {
|
||||
let actual = scope_object[name];
|
||||
let expected = scope_expectations[name];
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
// A copy of the scope types from mirror-debugger.js.
|
||||
var ScopeType = { Global: 0,
|
||||
Local: 1,
|
||||
With: 2,
|
||||
Closure: 3,
|
||||
Catch: 4,
|
||||
Block: 5 };
|
||||
|
||||
var f1 = (function F1(x) {
|
||||
function F2(y) {
|
||||
var z = x + y;
|
||||
{
|
||||
var w = 5;
|
||||
var v = "Capybara";
|
||||
var F3 = function(a, b) {
|
||||
function F4(p) {
|
||||
return p + a + b + z + w + v.length;
|
||||
}
|
||||
return F4;
|
||||
}
|
||||
return F3(4, 5);
|
||||
}
|
||||
}
|
||||
return F2(17);
|
||||
})(5);
|
||||
|
||||
var mirror = Debug.MakeMirror(f1);
|
||||
|
||||
assertEquals(4, mirror.scopeCount());
|
||||
|
||||
CheckScope(mirror.scope(0), { a: 4, b: 5 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(1), { z: 22, w: 5, v: "Capybara" }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(2), { x: 5 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(3), {}, ScopeType.Global);
|
||||
|
||||
var f2 = (function() {
|
||||
var v1 = 3;
|
||||
var v2 = 4;
|
||||
let l0 = 0;
|
||||
{
|
||||
var v3 = 5;
|
||||
let l1 = 6;
|
||||
let l2 = 7;
|
||||
{
|
||||
var v4 = 8;
|
||||
let l3 = 9;
|
||||
{
|
||||
var v5 = "Cat";
|
||||
let l4 = 11;
|
||||
var v6 = l4;
|
||||
return function() {
|
||||
return l0 + v1 + v3 + l2 + l3 + v6;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
var mirror = Debug.MakeMirror(f2);
|
||||
|
||||
assertEquals(5, mirror.scopeCount());
|
||||
|
||||
// Implementation artifact: l4 isn't used in closure, but still it is saved.
|
||||
CheckScope(mirror.scope(0), { l4: 11 }, ScopeType.Block);
|
||||
|
||||
CheckScope(mirror.scope(1), { l3: 9 }, ScopeType.Block);
|
||||
CheckScope(mirror.scope(2), { l1: 6, l2: 7 }, ScopeType.Block);
|
||||
CheckScope(mirror.scope(3), { v1:3, l0: 0, v3: 5, v6: 11 }, ScopeType.Closure);
|
||||
CheckScope(mirror.scope(4), {}, ScopeType.Global);
|
Loading…
Reference in New Issue
Block a user