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 {
*/
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.
* This is an experimental feature.
......
......@@ -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 {
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::Object> str;
......
......@@ -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 {
ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) {
......
......@@ -445,6 +445,10 @@ class Factory FINAL {
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
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.
Handle<JSProxy> NewJSProxy(Handle<Object> handler, Handle<Object> prototype);
......
......@@ -85,6 +85,8 @@ function MakeMirror(value, opt_transient) {
mirror = new MapMirror(value);
} else if (IS_SET(value) || IS_WEAKSET(value)) {
mirror = new SetMirror(value);
} else if (IS_MAP_ITERATOR(value) || IS_SET_ITERATOR(value)) {
mirror = new IteratorMirror(value);
} else if (ObjectIsPromise(value)) {
mirror = new PromiseMirror(value);
} else if (IS_GENERATOR(value)) {
......@@ -163,6 +165,7 @@ var SCOPE_TYPE = 'scope';
var PROMISE_TYPE = 'promise';
var MAP_TYPE = 'map';
var SET_TYPE = 'set';
var ITERATOR_TYPE = 'iterator';
var GENERATOR_TYPE = 'generator';
// Maximum length when sending strings through the JSON protocol.
......@@ -217,6 +220,7 @@ var ScopeType = { Global: 0,
// - PromiseMirror
// - MapMirror
// - SetMirror
// - IteratorMirror
// - GeneratorMirror
// - PropertyMirror
// - InternalPropertyMirror
......@@ -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.
*/
......@@ -1343,6 +1356,16 @@ function SetMirror(value) {
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.
* This will keep elements alive for WeakSets.
......@@ -1354,13 +1377,31 @@ SetMirror.prototype.values = function() {
return %GetWeakSetValues(this.value_);
}
var result = [];
var iter = %_CallFunction(this.value_, builtins.SetValues);
var next;
while (!(next = iter.next()).done) {
result.push(next.value);
return IteratorGetValues_(iter, builtins.SetIteratorNextJS);
};
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) {
}
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) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
......@@ -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) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
......
......@@ -310,6 +310,7 @@ namespace internal {
F(SetGetSize, 1, 1) \
\
F(SetIteratorInitialize, 3, 1) \
F(SetIteratorClone, 1, 1) \
F(SetIteratorNext, 2, 1) \
\
/* Harmony maps */ \
......@@ -322,6 +323,7 @@ namespace internal {
F(MapGetSize, 1, 1) \
\
F(MapIteratorInitialize, 3, 1) \
F(MapIteratorClone, 1, 1) \
F(MapIteratorNext, 2, 1) \
\
/* 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