Implement generator mirror
R=yangguo@chromium.org, aandrey@chromium.org BUG=v8:3292 LOG=N Review URL: https://codereview.chromium.org/580823002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24043 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
eca5875b9d
commit
3117f6b358
@ -87,6 +87,8 @@ function MakeMirror(value, opt_transient) {
|
||||
mirror = new SetMirror(value);
|
||||
} else if (ObjectIsPromise(value)) {
|
||||
mirror = new PromiseMirror(value);
|
||||
} else if (IS_GENERATOR(value)) {
|
||||
mirror = new GeneratorMirror(value);
|
||||
} else {
|
||||
mirror = new ObjectMirror(value, OBJECT_TYPE, opt_transient);
|
||||
}
|
||||
@ -161,6 +163,7 @@ var SCOPE_TYPE = 'scope';
|
||||
var PROMISE_TYPE = 'promise';
|
||||
var MAP_TYPE = 'map';
|
||||
var SET_TYPE = 'set';
|
||||
var GENERATOR_TYPE = 'generator';
|
||||
|
||||
// Maximum length when sending strings through the JSON protocol.
|
||||
var kMaxProtocolStringLength = 80;
|
||||
@ -214,6 +217,7 @@ var ScopeType = { Global: 0,
|
||||
// - PromiseMirror
|
||||
// - MapMirror
|
||||
// - SetMirror
|
||||
// - GeneratorMirror
|
||||
// - PropertyMirror
|
||||
// - InternalPropertyMirror
|
||||
// - FrameMirror
|
||||
@ -370,6 +374,15 @@ Mirror.prototype.isPromise = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the mirror reflects a generator object.
|
||||
* @returns {boolean} True if the mirror reflects a generator object
|
||||
*/
|
||||
Mirror.prototype.isGenerator = function() {
|
||||
return this instanceof GeneratorMirror;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the mirror reflects a property.
|
||||
* @returns {boolean} True if the mirror reflects a property
|
||||
@ -986,8 +999,8 @@ FunctionMirror.prototype.script = function() {
|
||||
* @return {Number or undefined} in-script position for the function
|
||||
*/
|
||||
FunctionMirror.prototype.sourcePosition_ = function() {
|
||||
// Return script if function is resolved. Otherwise just fall through
|
||||
// to return undefined.
|
||||
// Return position if function is resolved. Otherwise just fall
|
||||
// through to return undefined.
|
||||
if (this.resolved()) {
|
||||
return %FunctionGetScriptSourcePosition(this.value_);
|
||||
}
|
||||
@ -1351,6 +1364,66 @@ SetMirror.prototype.values = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mirror object for a Generator object.
|
||||
* @param {Object} data The Generator object
|
||||
* @constructor
|
||||
* @extends Mirror
|
||||
*/
|
||||
function GeneratorMirror(value) {
|
||||
%_CallFunction(this, value, GENERATOR_TYPE, ObjectMirror);
|
||||
}
|
||||
inherits(GeneratorMirror, ObjectMirror);
|
||||
|
||||
|
||||
GeneratorMirror.prototype.status = function() {
|
||||
var continuation = %GeneratorGetContinuation(this.value_);
|
||||
if (continuation < 0) return "running";
|
||||
if (continuation == 0) return "closed";
|
||||
return "suspended";
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.sourcePosition_ = function() {
|
||||
return %GeneratorGetSourcePosition(this.value_);
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.sourceLocation = function() {
|
||||
var pos = this.sourcePosition_();
|
||||
if (!IS_UNDEFINED(pos)) {
|
||||
var script = this.func().script();
|
||||
if (script) {
|
||||
return script.locationFromPosition(pos, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.func = function() {
|
||||
if (!this.func_) {
|
||||
this.func_ = MakeMirror(%GeneratorGetFunction(this.value_));
|
||||
}
|
||||
return this.func_;
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.context = function() {
|
||||
if (!this.context_) {
|
||||
this.context_ = new ContextMirror(%GeneratorGetContext(this.value_));
|
||||
}
|
||||
return this.context_;
|
||||
};
|
||||
|
||||
|
||||
GeneratorMirror.prototype.receiver = function() {
|
||||
if (!this.receiver_) {
|
||||
this.receiver_ = MakeMirror(%GeneratorGetReceiver(this.value_));
|
||||
}
|
||||
return this.receiver_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base mirror object for properties.
|
||||
* @param {ObjectMirror} mirror The mirror object having this property
|
||||
@ -2539,6 +2612,7 @@ JSONProtocolSerializer.prototype.serialize_ = function(mirror, reference,
|
||||
case ERROR_TYPE:
|
||||
case REGEXP_TYPE:
|
||||
case PROMISE_TYPE:
|
||||
case GENERATOR_TYPE:
|
||||
// Add object representation.
|
||||
this.serializeObject_(mirror, content, details);
|
||||
break;
|
||||
@ -2668,6 +2742,21 @@ JSONProtocolSerializer.prototype.serializeObject_ = function(mirror, content,
|
||||
}
|
||||
}
|
||||
|
||||
if (mirror.isGenerator()) {
|
||||
// Add generator specific properties.
|
||||
|
||||
// Either 'running', 'closed', or 'suspended'.
|
||||
content.status = mirror.status();
|
||||
|
||||
content.func = this.serializeReference(mirror.func())
|
||||
content.receiver = this.serializeReference(mirror.receiver())
|
||||
|
||||
// If the generator is suspended, the content add line/column properties.
|
||||
serializeLocationFields(mirror.sourceLocation(), content);
|
||||
|
||||
// TODO(wingo): Also serialize a reference to the context (scope chain).
|
||||
}
|
||||
|
||||
if (mirror.isDate()) {
|
||||
// Add date specific properties.
|
||||
content.value = mirror.value();
|
||||
|
@ -14627,6 +14627,65 @@ RUNTIME_FUNCTION(Runtime_GetV8Version) {
|
||||
}
|
||||
|
||||
|
||||
// Returns function of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetFunction) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->function();
|
||||
}
|
||||
|
||||
|
||||
// Returns context of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetContext) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->context();
|
||||
}
|
||||
|
||||
|
||||
// Returns receiver of generator activation.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetReceiver) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return generator->receiver();
|
||||
}
|
||||
|
||||
|
||||
// Returns generator continuation as a PC offset, or the magic -1 or 0 values.
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetContinuation) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
return Smi::FromInt(generator->continuation());
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_GeneratorGetSourcePosition) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSGeneratorObject, generator, 0);
|
||||
|
||||
if (generator->is_suspended()) {
|
||||
Handle<Code> code(generator->function()->code(), isolate);
|
||||
int offset = generator->continuation();
|
||||
|
||||
RUNTIME_ASSERT(0 <= offset && offset < code->Size());
|
||||
Address pc = code->address() + offset;
|
||||
|
||||
return Smi::FromInt(code->SourcePosition(pc));
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_Abort) {
|
||||
SealHandleScope shs(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
|
@ -210,6 +210,11 @@ namespace internal {
|
||||
F(GetScript, 1, 1) \
|
||||
F(CollectStackTrace, 2, 1) \
|
||||
F(GetV8Version, 0, 1) \
|
||||
F(GeneratorGetFunction, 1, 1) \
|
||||
F(GeneratorGetContext, 1, 1) \
|
||||
F(GeneratorGetReceiver, 1, 1) \
|
||||
F(GeneratorGetContinuation, 1, 1) \
|
||||
F(GeneratorGetSourcePosition, 1, 1) \
|
||||
\
|
||||
F(SetCode, 2, 1) \
|
||||
\
|
||||
|
84
test/mjsunit/es6/generators-mirror.js
Normal file
84
test/mjsunit/es6/generators-mirror.js
Normal file
@ -0,0 +1,84 @@
|
||||
// Copyright 2014 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: --expose-debug-as debug
|
||||
// Test the mirror object for functions.
|
||||
|
||||
function *generator(f) {
|
||||
"use strict";
|
||||
yield;
|
||||
f();
|
||||
yield;
|
||||
}
|
||||
|
||||
function MirrorRefCache(json_refs) {
|
||||
var tmp = eval('(' + json_refs + ')');
|
||||
this.refs_ = [];
|
||||
for (var i = 0; i < tmp.length; i++) {
|
||||
this.refs_[tmp[i].handle] = tmp[i];
|
||||
}
|
||||
}
|
||||
|
||||
MirrorRefCache.prototype.lookup = function(handle) {
|
||||
return this.refs_[handle];
|
||||
}
|
||||
|
||||
function TestGeneratorMirror(g, test) {
|
||||
// Create mirror and JSON representation.
|
||||
var mirror = debug.MakeMirror(g);
|
||||
var serializer = debug.MakeMirrorSerializer();
|
||||
var json = JSON.stringify(serializer.serializeValue(mirror));
|
||||
var refs = new MirrorRefCache(
|
||||
JSON.stringify(serializer.serializeReferencedObjects()));
|
||||
|
||||
// Check the mirror hierachy.
|
||||
assertTrue(mirror instanceof debug.Mirror);
|
||||
assertTrue(mirror instanceof debug.ValueMirror);
|
||||
assertTrue(mirror instanceof debug.ObjectMirror);
|
||||
assertTrue(mirror instanceof debug.GeneratorMirror);
|
||||
|
||||
// Check the mirror properties.
|
||||
assertTrue(mirror.isGenerator());
|
||||
assertEquals('generator', mirror.type());
|
||||
assertFalse(mirror.isPrimitive());
|
||||
assertEquals('Generator', mirror.className());
|
||||
|
||||
assertTrue(mirror.receiver().isUndefined());
|
||||
assertEquals(generator, mirror.func().value());
|
||||
|
||||
test(mirror);
|
||||
}
|
||||
|
||||
var iter = generator(function () {
|
||||
assertEquals('running', debug.MakeMirror(iter).status());
|
||||
})
|
||||
|
||||
// Note that line numbers are 0-based, not 1-based.
|
||||
function assertSourceLocation(loc, line, column) {
|
||||
assertEquals(line, loc.line);
|
||||
assertEquals(column, loc.column);
|
||||
}
|
||||
|
||||
TestGeneratorMirror(iter, function (mirror) {
|
||||
assertEquals('suspended', mirror.status())
|
||||
assertSourceLocation(mirror.sourceLocation(), 7, 19);
|
||||
});
|
||||
|
||||
iter.next();
|
||||
TestGeneratorMirror(iter, function (mirror) {
|
||||
assertEquals('suspended', mirror.status())
|
||||
assertSourceLocation(mirror.sourceLocation(), 9, 2);
|
||||
});
|
||||
|
||||
iter.next();
|
||||
TestGeneratorMirror(iter, function (mirror) {
|
||||
assertEquals('suspended', mirror.status())
|
||||
assertSourceLocation(mirror.sourceLocation(), 11, 2);
|
||||
});
|
||||
|
||||
iter.next();
|
||||
TestGeneratorMirror(iter, function (mirror) {
|
||||
assertEquals('closed', mirror.status())
|
||||
assertEquals(undefined, mirror.sourceLocation());
|
||||
});
|
Loading…
Reference in New Issue
Block a user