Commit 4cff8218 authored by jgruber's avatar jgruber Committed by Commit bot

Allow access to scopes of suspended generator objects

The scopes of suspended generators can now be accessed through GeneratorMirror
(similar to FrameMirror).

BUG=v8:5235

Review-Url: https://codereview.chromium.org/2228393002
Cr-Commit-Position: refs/heads/master@{#38530}
parent a91811e1
...@@ -125,6 +125,19 @@ ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function) ...@@ -125,6 +125,19 @@ ScopeIterator::ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
UnwrapEvaluationContext(); UnwrapEvaluationContext();
} }
ScopeIterator::ScopeIterator(Isolate* isolate,
Handle<JSGeneratorObject> generator)
: isolate_(isolate),
frame_inspector_(NULL),
context_(generator->context()),
seen_script_scope_(false),
failed_(false) {
if (!generator->function()->shared()->IsSubjectToDebugging()) {
context_ = Handle<Context>();
}
UnwrapEvaluationContext();
}
void ScopeIterator::UnwrapEvaluationContext() { void ScopeIterator::UnwrapEvaluationContext() {
while (true) { while (true) {
if (context_.is_null()) return; if (context_.is_null()) return;
...@@ -623,6 +636,7 @@ bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info, ...@@ -623,6 +636,7 @@ bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info, bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
Handle<String> variable_name, Handle<String> variable_name,
Handle<Object> new_value) { Handle<Object> new_value) {
if (frame_inspector_ == nullptr) return false;
JavaScriptFrame* frame = GetFrame(); JavaScriptFrame* frame = GetFrame();
// Setting stack locals of optimized frames is not supported. // Setting stack locals of optimized frames is not supported.
if (frame->is_optimized()) return false; if (frame->is_optimized()) return false;
......
...@@ -43,6 +43,7 @@ class ScopeIterator { ...@@ -43,6 +43,7 @@ class ScopeIterator {
Option options = DEFAULT); Option options = DEFAULT);
ScopeIterator(Isolate* isolate, Handle<JSFunction> function); ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
ScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator);
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails(); MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
......
...@@ -1022,7 +1022,7 @@ FunctionMirror.prototype.scopeCount = function() { ...@@ -1022,7 +1022,7 @@ FunctionMirror.prototype.scopeCount = function() {
FunctionMirror.prototype.scope = function(index) { FunctionMirror.prototype.scope = function(index) {
if (this.resolved()) { if (this.resolved()) {
return new ScopeMirror(UNDEFINED, this, index); return new ScopeMirror(UNDEFINED, this, UNDEFINED, index);
} }
}; };
...@@ -1451,6 +1451,27 @@ GeneratorMirror.prototype.receiver = function() { ...@@ -1451,6 +1451,27 @@ GeneratorMirror.prototype.receiver = function() {
}; };
GeneratorMirror.prototype.scopeCount = function() {
// This value can change over time as the underlying generator is suspended
// at different locations.
return %GetGeneratorScopeCount(this.value());
};
GeneratorMirror.prototype.scope = function(index) {
return new ScopeMirror(UNDEFINED, UNDEFINED, this, index);
};
GeneratorMirror.prototype.allScopes = function() {
var scopes = [];
for (let i = 0; i < this.scopeCount(); i++) {
scopes.push(this.scope(i));
}
return scopes;
};
/** /**
* Base mirror object for properties. * Base mirror object for properties.
* @param {ObjectMirror} mirror The mirror object having this property * @param {ObjectMirror} mirror The mirror object having this property
...@@ -1973,7 +1994,7 @@ FrameMirror.prototype.scopeCount = function() { ...@@ -1973,7 +1994,7 @@ FrameMirror.prototype.scopeCount = function() {
FrameMirror.prototype.scope = function(index) { FrameMirror.prototype.scope = function(index) {
return new ScopeMirror(this, UNDEFINED, index); return new ScopeMirror(this, UNDEFINED, UNDEFINED, index);
}; };
...@@ -1984,7 +2005,8 @@ FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) { ...@@ -1984,7 +2005,8 @@ FrameMirror.prototype.allScopes = function(opt_ignore_nested_scopes) {
!!opt_ignore_nested_scopes); !!opt_ignore_nested_scopes);
var result = []; var result = [];
for (var i = 0; i < scopeDetails.length; ++i) { for (var i = 0; i < scopeDetails.length; ++i) {
result.push(new ScopeMirror(this, UNDEFINED, i, scopeDetails[i])); result.push(new ScopeMirror(this, UNDEFINED, UNDEFINED, i,
scopeDetails[i]));
} }
return result; return result;
}; };
...@@ -2163,7 +2185,7 @@ var kScopeDetailsStartPositionIndex = 3; ...@@ -2163,7 +2185,7 @@ var kScopeDetailsStartPositionIndex = 3;
var kScopeDetailsEndPositionIndex = 4; var kScopeDetailsEndPositionIndex = 4;
var kScopeDetailsFunctionIndex = 5; var kScopeDetailsFunctionIndex = 5;
function ScopeDetails(frame, fun, index, opt_details) { function ScopeDetails(frame, fun, gen, index, opt_details) {
if (frame) { if (frame) {
this.break_id_ = frame.break_id_; this.break_id_ = frame.break_id_;
this.details_ = opt_details || this.details_ = opt_details ||
...@@ -2173,10 +2195,15 @@ function ScopeDetails(frame, fun, index, opt_details) { ...@@ -2173,10 +2195,15 @@ function ScopeDetails(frame, fun, index, opt_details) {
index); index);
this.frame_id_ = frame.details_.frameId(); this.frame_id_ = frame.details_.frameId();
this.inlined_frame_id_ = frame.details_.inlinedFrameIndex(); this.inlined_frame_id_ = frame.details_.inlinedFrameIndex();
} else { } else if (fun) {
this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index); this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index);
this.fun_value_ = fun.value(); this.fun_value_ = fun.value();
this.break_id_ = UNDEFINED; this.break_id_ = UNDEFINED;
} else {
this.details_ =
opt_details || %GetGeneratorScopeDetails(gen.value(), index);
this.gen_value_ = gen.value();
this.break_id_ = UNDEFINED;
} }
this.index_ = index; this.index_ = index;
} }
...@@ -2235,9 +2262,12 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) { ...@@ -2235,9 +2262,12 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
%CheckExecutionState(this.break_id_); %CheckExecutionState(this.break_id_);
raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_, raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_,
this.inlined_frame_id_, this.index_, name, new_value); this.inlined_frame_id_, this.index_, name, new_value);
} else { } else if (!IS_UNDEFINED(this.fun_value_)) {
raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_, raw_res = %SetScopeVariableValue(this.fun_value_, null, null, this.index_,
name, new_value); name, new_value);
} else {
raw_res = %SetScopeVariableValue(this.gen_value_, null, null, this.index_,
name, new_value);
} }
if (!raw_res) throw %make_error(kDebugger, "Failed to set variable value"); if (!raw_res) throw %make_error(kDebugger, "Failed to set variable value");
}; };
...@@ -2248,12 +2278,13 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) { ...@@ -2248,12 +2278,13 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
* be specified. * 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 {FunctionMirror} function The function this scope is a part of
* @param {GeneratorMirror} gen The generator this scope is a part of
* @param {number} index The scope index in the frame * @param {number} index The scope index in the frame
* @param {Array=} opt_details Raw scope details data * @param {Array=} opt_details Raw scope details data
* @constructor * @constructor
* @extends Mirror * @extends Mirror
*/ */
function ScopeMirror(frame, fun, index, opt_details) { function ScopeMirror(frame, fun, gen, index, opt_details) {
%_Call(Mirror, this, MirrorType.SCOPE_TYPE); %_Call(Mirror, this, MirrorType.SCOPE_TYPE);
if (frame) { if (frame) {
this.frame_index_ = frame.index_; this.frame_index_ = frame.index_;
...@@ -2261,7 +2292,7 @@ function ScopeMirror(frame, fun, index, opt_details) { ...@@ -2261,7 +2292,7 @@ function ScopeMirror(frame, fun, index, opt_details) {
this.frame_index_ = UNDEFINED; this.frame_index_ = UNDEFINED;
} }
this.scope_index_ = index; this.scope_index_ = index;
this.details_ = new ScopeDetails(frame, fun, index, opt_details); this.details_ = new ScopeDetails(frame, fun, gen, index, opt_details);
} }
inherits(ScopeMirror, Mirror); inherits(ScopeMirror, Mirror);
......
...@@ -919,6 +919,48 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) { ...@@ -919,6 +919,48 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails()); RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
} }
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeCount) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
if (!args[0]->IsJSGeneratorObject()) return Smi::FromInt(0);
// Check arguments.
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
// Count the visible scopes.
int n = 0;
for (ScopeIterator it(isolate, gen); !it.Done(); it.Next()) {
n++;
}
return Smi::FromInt(n);
}
RUNTIME_FUNCTION(Runtime_GetGeneratorScopeDetails) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
if (!args[0]->IsJSGeneratorObject()) {
return *isolate->factory()->undefined_value();
}
// Check arguments.
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
// Find the requested scope.
int n = 0;
ScopeIterator it(isolate, gen);
for (; !it.Done() && n < index; it.Next()) {
n++;
}
if (it.Done()) {
return isolate->heap()->undefined_value();
}
RETURN_RESULT_OR_FAILURE(isolate, it.MaterializeScopeDetails());
}
static bool SetScopeVariableValue(ScopeIterator* it, int index, static bool SetScopeVariableValue(ScopeIterator* it, int index,
Handle<String> variable_name, Handle<String> variable_name,
...@@ -967,10 +1009,14 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) { ...@@ -967,10 +1009,14 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
ScopeIterator it(isolate, &frame_inspector); ScopeIterator it(isolate, &frame_inspector);
res = SetScopeVariableValue(&it, index, variable_name, new_value); res = SetScopeVariableValue(&it, index, variable_name, new_value);
} else { } else if (args[0]->IsJSFunction()) {
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ScopeIterator it(isolate, fun); ScopeIterator it(isolate, fun);
res = SetScopeVariableValue(&it, index, variable_name, new_value); res = SetScopeVariableValue(&it, index, variable_name, new_value);
} else {
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, gen, 0);
ScopeIterator it(isolate, gen);
res = SetScopeVariableValue(&it, index, variable_name, new_value);
} }
return isolate->heap()->ToBoolean(res); return isolate->heap()->ToBoolean(res);
......
...@@ -156,6 +156,8 @@ namespace internal { ...@@ -156,6 +156,8 @@ namespace internal {
F(GetAllScopesDetails, 4, 1) \ F(GetAllScopesDetails, 4, 1) \
F(GetFunctionScopeCount, 1, 1) \ F(GetFunctionScopeCount, 1, 1) \
F(GetFunctionScopeDetails, 2, 1) \ F(GetFunctionScopeDetails, 2, 1) \
F(GetGeneratorScopeCount, 1, 1) \
F(GetGeneratorScopeDetails, 2, 1) \
F(SetScopeVariableValue, 6, 1) \ F(SetScopeVariableValue, 6, 1) \
F(DebugPrintScopes, 0, 1) \ F(DebugPrintScopes, 0, 1) \
F(SetBreakPointsActive, 1, 1) \ F(SetBreakPointsActive, 1, 1) \
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment