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)) {
|
if (request.arguments && !IS_UNDEFINED(request.arguments.frameNumber)) {
|
||||||
frame_index = request.arguments.frameNumber;
|
frame_index = request.arguments.frameNumber;
|
||||||
if (frame_index < 0 || this.exec_state_.frameCount() <= frame_index) {
|
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);
|
return this.exec_state_.frame(frame_index);
|
||||||
} else {
|
} else {
|
||||||
@ -1966,20 +1966,44 @@ DebugCommandProcessor.prototype.frameForScopeRequest_ = function(request) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
|
// 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.
|
// No frames no scopes.
|
||||||
if (this.exec_state_.frameCount() == 0) {
|
if (this.exec_state_.frameCount() == 0) {
|
||||||
return response.failed('No scopes');
|
throw new Error('No scopes');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the frame for which the scopes are requested.
|
// Get the frame for which the scopes are requested.
|
||||||
var frame = this.frameForScopeRequest_(request);
|
var frame = this.frameForScopeRequest_(request);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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 = [];
|
var scopes = [];
|
||||||
for (var i = 0; i < total_scopes; i++) {
|
for (var i = 0; i < total_scopes; i++) {
|
||||||
scopes.push(frame.scope(i));
|
scopes.push(scope_holder.scope(i));
|
||||||
}
|
}
|
||||||
response.body = {
|
response.body = {
|
||||||
fromScope: 0,
|
fromScope: 0,
|
||||||
@ -1991,24 +2015,19 @@ DebugCommandProcessor.prototype.scopesRequest_ = function(request, response) {
|
|||||||
|
|
||||||
|
|
||||||
DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
|
DebugCommandProcessor.prototype.scopeRequest_ = function(request, response) {
|
||||||
// No frames no scopes.
|
// Get the frame or function for which the scope is requested.
|
||||||
if (this.exec_state_.frameCount() == 0) {
|
var scope_holder = this.scopeHolderForScopeRequest_(request);
|
||||||
return response.failed('No scopes');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the frame for which the scope is requested.
|
|
||||||
var frame = this.frameForScopeRequest_(request);
|
|
||||||
|
|
||||||
// With no scope argument just return top scope.
|
// With no scope argument just return top scope.
|
||||||
var scope_index = 0;
|
var scope_index = 0;
|
||||||
if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
|
if (request.arguments && !IS_UNDEFINED(request.arguments.number)) {
|
||||||
scope_index = %ToNumber(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');
|
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() {
|
FunctionMirror.prototype.toText = function() {
|
||||||
return this.source();
|
return this.source();
|
||||||
};
|
};
|
||||||
@ -1589,7 +1605,7 @@ FrameMirror.prototype.scopeCount = function() {
|
|||||||
|
|
||||||
|
|
||||||
FrameMirror.prototype.scope = function(index) {
|
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 kScopeDetailsTypeIndex = 0;
|
||||||
var kScopeDetailsObjectIndex = 1;
|
var kScopeDetailsObjectIndex = 1;
|
||||||
|
|
||||||
function ScopeDetails(frame, index) {
|
function ScopeDetails(frame, fun, index) {
|
||||||
|
if (frame) {
|
||||||
this.break_id_ = frame.break_id_;
|
this.break_id_ = frame.break_id_;
|
||||||
this.details_ = %GetScopeDetails(frame.break_id_,
|
this.details_ = %GetScopeDetails(frame.break_id_,
|
||||||
frame.details_.frameId(),
|
frame.details_.frameId(),
|
||||||
frame.details_.inlinedFrameIndex(),
|
frame.details_.inlinedFrameIndex(),
|
||||||
index);
|
index);
|
||||||
|
} else {
|
||||||
|
this.details_ = %GetFunctionScopeDetails(fun.value(), index);
|
||||||
|
this.break_id_ = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ScopeDetails.prototype.type = function() {
|
ScopeDetails.prototype.type = function() {
|
||||||
|
if (!IS_UNDEFINED(this.break_id_)) {
|
||||||
%CheckExecutionState(this.break_id_);
|
%CheckExecutionState(this.break_id_);
|
||||||
|
}
|
||||||
return this.details_[kScopeDetailsTypeIndex];
|
return this.details_[kScopeDetailsTypeIndex];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ScopeDetails.prototype.object = function() {
|
ScopeDetails.prototype.object = function() {
|
||||||
|
if (!IS_UNDEFINED(this.break_id_)) {
|
||||||
%CheckExecutionState(this.break_id_);
|
%CheckExecutionState(this.break_id_);
|
||||||
|
}
|
||||||
return this.details_[kScopeDetailsObjectIndex];
|
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 {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
|
* @param {number} index The scope index in the frame
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends Mirror
|
* @extends Mirror
|
||||||
*/
|
*/
|
||||||
function ScopeMirror(frame, index) {
|
function ScopeMirror(frame, function, index) {
|
||||||
%_CallFunction(this, SCOPE_TYPE, Mirror);
|
%_CallFunction(this, SCOPE_TYPE, Mirror);
|
||||||
|
if (frame) {
|
||||||
this.frame_index_ = frame.index_;
|
this.frame_index_ = frame.index_;
|
||||||
|
} else {
|
||||||
|
this.frame_index_ = undefined;
|
||||||
|
}
|
||||||
this.scope_index_ = index;
|
this.scope_index_ = index;
|
||||||
this.details_ = new ScopeDetails(frame, index);
|
this.details_ = new ScopeDetails(frame, function, index);
|
||||||
}
|
}
|
||||||
inherits(ScopeMirror, Mirror);
|
inherits(ScopeMirror, Mirror);
|
||||||
|
|
||||||
@ -2281,6 +2312,15 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
|
|||||||
|
|
||||||
serializeLocationFields(mirror.sourceLocation(), 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.
|
// Add date specific properties.
|
||||||
|
@ -11018,10 +11018,10 @@ static Handle<JSObject> MaterializeModuleScope(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Iterate over the actual scopes visible from a stack frame. The iteration
|
// Iterate over the actual scopes visible from a stack frame or from a closure.
|
||||||
// proceeds from the innermost visible nested scope outwards. All scopes are
|
// The iteration proceeds from the innermost visible nested scope outwards.
|
||||||
// backed by an actual context except the local scope, which is inserted
|
// All scopes are backed by an actual context except the local scope,
|
||||||
// "artificially" in the context chain.
|
// which is inserted "artificially" in the context chain.
|
||||||
class ScopeIterator {
|
class ScopeIterator {
|
||||||
public:
|
public:
|
||||||
enum ScopeType {
|
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?
|
// More scopes?
|
||||||
bool Done() { return context_.is_null(); }
|
bool Done() { return context_.is_null(); }
|
||||||
|
|
||||||
@ -11342,6 +11354,22 @@ static const int kScopeDetailsTypeIndex = 0;
|
|||||||
static const int kScopeDetailsObjectIndex = 1;
|
static const int kScopeDetailsObjectIndex = 1;
|
||||||
static const int kScopeDetailsSize = 2;
|
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
|
// Return an array with scope details
|
||||||
// args[0]: number: break id
|
// args[0]: number: break id
|
||||||
// args[1]: number: frame index
|
// args[1]: number: frame index
|
||||||
@ -11379,18 +11407,46 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
|
|||||||
if (it.Done()) {
|
if (it.Done()) {
|
||||||
return isolate->heap()->undefined_value();
|
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.
|
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionScopeCount) {
|
||||||
details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
|
HandleScope scope(isolate);
|
||||||
Handle<JSObject> scope_object = it.ScopeObject();
|
ASSERT(args.length() == 1);
|
||||||
RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
|
|
||||||
details->set(kScopeDetailsObjectIndex, *scope_object);
|
|
||||||
|
|
||||||
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(GetFrameDetails, 2, 1) \
|
||||||
F(GetScopeCount, 2, 1) \
|
F(GetScopeCount, 2, 1) \
|
||||||
F(GetScopeDetails, 4, 1) \
|
F(GetScopeDetails, 4, 1) \
|
||||||
|
F(GetFunctionScopeCount, 1, 1) \
|
||||||
|
F(GetFunctionScopeDetails, 2, 1) \
|
||||||
F(DebugPrintScopes, 0, 1) \
|
F(DebugPrintScopes, 0, 1) \
|
||||||
F(GetThreadCount, 1, 1) \
|
F(GetThreadCount, 1, 1) \
|
||||||
F(GetThreadDetails, 2, 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