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)
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() {
while (true) {
if (context_.is_null()) return;
......@@ -623,6 +636,7 @@ bool ScopeIterator::SetParameterValue(Handle<ScopeInfo> scope_info,
bool ScopeIterator::SetStackVariableValue(Handle<ScopeInfo> scope_info,
Handle<String> variable_name,
Handle<Object> new_value) {
if (frame_inspector_ == nullptr) return false;
JavaScriptFrame* frame = GetFrame();
// Setting stack locals of optimized frames is not supported.
if (frame->is_optimized()) return false;
......
......@@ -43,6 +43,7 @@ class ScopeIterator {
Option options = DEFAULT);
ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
ScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator);
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
......
......@@ -1022,7 +1022,7 @@ FunctionMirror.prototype.scopeCount = function() {
FunctionMirror.prototype.scope = function(index) {
if (this.resolved()) {
return new ScopeMirror(UNDEFINED, this, index);
return new ScopeMirror(UNDEFINED, this, UNDEFINED, index);
}
};
......@@ -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.
* @param {ObjectMirror} mirror The mirror object having this property
......@@ -1973,7 +1994,7 @@ FrameMirror.prototype.scopeCount = function() {
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) {
!!opt_ignore_nested_scopes);
var result = [];
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;
};
......@@ -2163,7 +2185,7 @@ var kScopeDetailsStartPositionIndex = 3;
var kScopeDetailsEndPositionIndex = 4;
var kScopeDetailsFunctionIndex = 5;
function ScopeDetails(frame, fun, index, opt_details) {
function ScopeDetails(frame, fun, gen, index, opt_details) {
if (frame) {
this.break_id_ = frame.break_id_;
this.details_ = opt_details ||
......@@ -2173,10 +2195,15 @@ function ScopeDetails(frame, fun, index, opt_details) {
index);
this.frame_id_ = frame.details_.frameId();
this.inlined_frame_id_ = frame.details_.inlinedFrameIndex();
} else {
} else if (fun) {
this.details_ = opt_details || %GetFunctionScopeDetails(fun.value(), index);
this.fun_value_ = fun.value();
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;
}
......@@ -2235,9 +2262,12 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
%CheckExecutionState(this.break_id_);
raw_res = %SetScopeVariableValue(this.break_id_, this.frame_id_,
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_,
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");
};
......@@ -2248,12 +2278,13 @@ ScopeDetails.prototype.setVariableValueImpl = function(name, new_value) {
* 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 {GeneratorMirror} gen The generator this scope is a part of
* @param {number} index The scope index in the frame
* @param {Array=} opt_details Raw scope details data
* @constructor
* @extends Mirror
*/
function ScopeMirror(frame, fun, index, opt_details) {
function ScopeMirror(frame, fun, gen, index, opt_details) {
%_Call(Mirror, this, MirrorType.SCOPE_TYPE);
if (frame) {
this.frame_index_ = frame.index_;
......@@ -2261,7 +2292,7 @@ function ScopeMirror(frame, fun, index, opt_details) {
this.frame_index_ = UNDEFINED;
}
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);
......
......@@ -919,6 +919,48 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
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,
Handle<String> variable_name,
......@@ -967,10 +1009,14 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
ScopeIterator it(isolate, &frame_inspector);
res = SetScopeVariableValue(&it, index, variable_name, new_value);
} else {
} else if (args[0]->IsJSFunction()) {
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ScopeIterator it(isolate, fun);
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);
......
......@@ -156,6 +156,8 @@ namespace internal {
F(GetAllScopesDetails, 4, 1) \
F(GetFunctionScopeCount, 1, 1) \
F(GetFunctionScopeDetails, 2, 1) \
F(GetGeneratorScopeCount, 1, 1) \
F(GetGeneratorScopeDetails, 2, 1) \
F(SetScopeVariableValue, 6, 1) \
F(DebugPrintScopes, 0, 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