Commit 35eaced2 authored by aandrey@chromium.org's avatar aandrey@chromium.org

Add debug mirror support for ES6 Map/Set iterators.

This is to show values preview of an iterator in DevTools console.

API=v8::Value::IsMapIterator, v8::Value::IsSetIterator
BUG=chromium:427868
R=arv@chromium.org, yangguo@chromium.org, adamk@chromium.org
LOG=Y

Review URL: https://codereview.chromium.org/693813002

Cr-Commit-Position: refs/heads/master@{#25100}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25100 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d7bc74f8
...@@ -1625,6 +1625,18 @@ class V8_EXPORT Value : public Data { ...@@ -1625,6 +1625,18 @@ class V8_EXPORT Value : public Data {
*/ */
bool IsSet() const; bool IsSet() const;
/**
* Returns true if this value is a Map Iterator.
* This is an experimental feature.
*/
bool IsMapIterator() const;
/**
* Returns true if this value is a Set Iterator.
* This is an experimental feature.
*/
bool IsSetIterator() const;
/** /**
* Returns true if this value is a WeakMap. * Returns true if this value is a WeakMap.
* This is an experimental feature. * This is an experimental feature.
......
...@@ -2571,6 +2571,16 @@ bool Value::IsGeneratorObject() const { ...@@ -2571,6 +2571,16 @@ bool Value::IsGeneratorObject() const {
} }
bool Value::IsMapIterator() const {
return Utils::OpenHandle(this)->IsJSMapIterator();
}
bool Value::IsSetIterator() const {
return Utils::OpenHandle(this)->IsJSSetIterator();
}
Local<String> Value::ToString(Isolate* v8_isolate) const { Local<String> Value::ToString(Isolate* v8_isolate) const {
i::Handle<i::Object> obj = Utils::OpenHandle(this); i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> str; i::Handle<i::Object> str;
......
...@@ -1722,6 +1722,22 @@ Handle<JSDataView> Factory::NewJSDataView() { ...@@ -1722,6 +1722,22 @@ Handle<JSDataView> Factory::NewJSDataView() {
} }
Handle<JSMapIterator> Factory::NewJSMapIterator() {
Handle<Map> map(isolate()->native_context()->map_iterator_map());
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateJSObjectFromMap(*map),
JSMapIterator);
}
Handle<JSSetIterator> Factory::NewJSSetIterator() {
Handle<Map> map(isolate()->native_context()->set_iterator_map());
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->AllocateJSObjectFromMap(*map),
JSSetIterator);
}
namespace { namespace {
ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) { ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
......
...@@ -445,6 +445,10 @@ class Factory FINAL { ...@@ -445,6 +445,10 @@ class Factory FINAL {
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer, Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t byte_length); size_t byte_offset, size_t byte_length);
// TODO(aandrey): Maybe these should take table, index and kind arguments.
Handle<JSMapIterator> NewJSMapIterator();
Handle<JSSetIterator> NewJSSetIterator();
// Allocates a Harmony proxy. // Allocates a Harmony proxy.
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype); Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
......
...@@ -85,6 +85,8 @@ function MakeMirror(value, opt_transient) { ...@@ -85,6 +85,8 @@ function MakeMirror(value, opt_transient) {
mirror = new MapMirror(value); mirror = new MapMirror(value);
} else if (IS_SET(value) || IS_WEAKSET(value)) { } else if (IS_SET(value) || IS_WEAKSET(value)) {
mirror = new SetMirror(value); mirror = new SetMirror(value);
} else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
mirror = new IteratorMirror(value);
} else if (ObjectIsPromise(value)) { } else if (ObjectIsPromise(value)) {
mirror = new PromiseMirror(value); mirror = new PromiseMirror(value);
} else if (IS_GENERATOR(value)) { } else if (IS_GENERATOR(value)) {
...@@ -163,6 +165,7 @@ var SCOPE_TYPE = 'scope'; ...@@ -163,6 +165,7 @@ var SCOPE_TYPE = 'scope';
var PROMISE_TYPE = 'promise'; var PROMISE_TYPE = 'promise';
var MAP_TYPE = 'map'; var MAP_TYPE = 'map';
var SET_TYPE = 'set'; var SET_TYPE = 'set';
var ITERATOR_TYPE = 'iterator';
var GENERATOR_TYPE = 'generator'; var GENERATOR_TYPE = 'generator';
// Maximum length when sending strings through the JSON protocol. // Maximum length when sending strings through the JSON protocol.
...@@ -217,6 +220,7 @@ var ScopeType = { Global: 0, ...@@ -217,6 +220,7 @@ var ScopeType = { Global: 0,
// - PromiseMirror // - PromiseMirror
// - MapMirror // - MapMirror
// - SetMirror // - SetMirror
// - IteratorMirror
// - GeneratorMirror // - GeneratorMirror
// - PropertyMirror // - PropertyMirror
// - InternalPropertyMirror // - InternalPropertyMirror
...@@ -455,6 +459,15 @@ Mirror.prototype.isSet = function() { ...@@ -455,6 +459,15 @@ Mirror.prototype.isSet = function() {
}; };
/**
* Check whether the mirror reflects an iterator.
* @returns {boolean} True if the mirror reflects an iterator
*/
Mirror.prototype.isIterator = function() {
return this instanceof IteratorMirror;
};
/** /**
* Allocate a handle id for this object. * Allocate a handle id for this object.
*/ */
...@@ -1343,6 +1356,16 @@ function SetMirror(value) { ...@@ -1343,6 +1356,16 @@ function SetMirror(value) {
inherits(SetMirror, ObjectMirror); inherits(SetMirror, ObjectMirror);
function IteratorGetValues_(iter, next_function) {
var result = [];
var next;
while (!(next = %_CallFunction(iter, next_function)).done) {
result.push(next.value);
}
return result;
}
/** /**
* Returns an array of elements of a set. * Returns an array of elements of a set.
* This will keep elements alive for WeakSets. * This will keep elements alive for WeakSets.
...@@ -1354,13 +1377,31 @@ SetMirror.prototype.values = function() { ...@@ -1354,13 +1377,31 @@ SetMirror.prototype.values = function() {
return %GetWeakSetValues(this.value_); return %GetWeakSetValues(this.value_);
} }
var result = [];
var iter = %_CallFunction(this.value_, builtins.SetValues); var iter = %_CallFunction(this.value_, builtins.SetValues);
var next; return IteratorGetValues_(iter, builtins.SetIteratorNextJS);
while (!(next = iter.next()).done) { };
result.push(next.value);
function IteratorMirror(value) {
%_CallFunction(this, value, ITERATOR_TYPE, ObjectMirror);
}
inherits(IteratorMirror, ObjectMirror);
/**
* Returns a preview of elements of an iterator.
* Does not change the backing iterator state.
*
* @returns {Array.<Object>} Array of elements of an iterator.
*/
IteratorMirror.prototype.preview = function() {
if (IS_MAP_ITERATOR(this.value_)) {
return IteratorGetValues_(%MapIteratorClone(this.value_),
builtins.MapIteratorNextJS);
} else if (IS_SET_ITERATOR(this.value_)) {
return IteratorGetValues_(%SetIteratorClone(this.value_),
builtins.SetIteratorNextJS);
} }
return result;
}; };
......
...@@ -92,6 +92,20 @@ RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) { ...@@ -92,6 +92,20 @@ RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
} }
RUNTIME_FUNCTION(Runtime_SetIteratorClone) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
Handle<JSSetIterator> result = isolate->factory()->NewJSSetIterator();
result->set_table(holder->table());
result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
return *result;
}
RUNTIME_FUNCTION(Runtime_SetIteratorNext) { RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK(args.length() == 2); DCHECK(args.length() == 2);
...@@ -197,6 +211,20 @@ RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) { ...@@ -197,6 +211,20 @@ RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
} }
RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
Handle<JSMapIterator> result = isolate->factory()->NewJSMapIterator();
result->set_table(holder->table());
result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
return *result;
}
RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) { RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 1);
......
...@@ -310,6 +310,7 @@ namespace internal { ...@@ -310,6 +310,7 @@ namespace internal {
F(SetGetSize, 1, 1) \ F(SetGetSize, 1, 1) \
\ \
F(SetIteratorInitialize, 3, 1) \ F(SetIteratorInitialize, 3, 1) \
F(SetIteratorClone, 1, 1) \
F(SetIteratorNext, 2, 1) \ F(SetIteratorNext, 2, 1) \
\ \
/* Harmony maps */ \ /* Harmony maps */ \
...@@ -322,6 +323,7 @@ namespace internal { ...@@ -322,6 +323,7 @@ namespace internal {
F(MapGetSize, 1, 1) \ F(MapGetSize, 1, 1) \
\ \
F(MapIteratorInitialize, 3, 1) \ F(MapIteratorInitialize, 3, 1) \
F(MapIteratorClone, 1, 1) \
F(MapIteratorNext, 2, 1) \ F(MapIteratorNext, 2, 1) \
\ \
/* Harmony weak maps and sets */ \ /* Harmony weak maps and sets */ \
......
// 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 collection iterators.
function testIteratorMirror(iter, offset, expected) {
while (offset-- > 0) iter.next();
var mirror = debug.MakeMirror(iter);
assertTrue(mirror.isIterator());
var preview = mirror.preview();
assertArrayEquals(expected, preview);
// Check that iterator has not changed after taking preview.
var values = [];
for (var i of iter) values.push(i);
assertArrayEquals(expected, values);
}
var o1 = { foo: 1 };
var o2 = { foo: 2 };
var map = new Map();
map.set(41, 42);
map.set(o1, o2);
testIteratorMirror(map.keys(), 0, [41, o1]);
testIteratorMirror(map.values(), 0, [42, o2]);
testIteratorMirror(map.entries(), 0, [[41, 42], [o1, o2]]);
testIteratorMirror(map.keys(), 1, [o1]);
testIteratorMirror(map.values(), 1, [o2]);
testIteratorMirror(map.entries(), 1, [[o1, o2]]);
testIteratorMirror(map.keys(), 2, []);
testIteratorMirror(map.values(), 2, []);
testIteratorMirror(map.entries(), 2, []);
var set = new Set();
set.add(41);
set.add(42);
set.add(o1);
set.add(o2);
testIteratorMirror(set.keys(), 0, [41, 42, o1, o2]);
testIteratorMirror(set.values(), 0, [41, 42, o1, o2]);
testIteratorMirror(set.entries(), 0, [[41, 41], [42, 42], [o1, o1], [o2, o2]]);
testIteratorMirror(set.keys(), 1, [42, o1, o2]);
testIteratorMirror(set.values(), 1, [42, o1, o2]);
testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1], [o2, o2]]);
testIteratorMirror(set.keys(), 3, [o2]);
testIteratorMirror(set.values(), 3, [o2]);
testIteratorMirror(set.entries(), 3, [[o2, o2]]);
testIteratorMirror(set.keys(), 5, []);
testIteratorMirror(set.values(), 5, []);
testIteratorMirror(set.entries(), 5, []);
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