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.
*/
}
+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;
}
+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) {
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);
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)) {
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.
// - PromiseMirror
// - MapMirror
// - SetMirror
+// - IteratorMirror
// - GeneratorMirror
// - PropertyMirror
// - InternalPropertyMirror
/**
+ * 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.
*/
Mirror.prototype.allocateHandle_ = function() {
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.
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;
};
}
+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);
}
+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);
F(SetGetSize, 1, 1) \
\
F(SetIteratorInitialize, 3, 1) \
+ F(SetIteratorClone, 1, 1) \
F(SetIteratorNext, 2, 1) \
\
/* Harmony maps */ \
F(MapGetSize, 1, 1) \
\
F(MapIteratorInitialize, 3, 1) \
+ F(MapIteratorClone, 1, 1) \
F(MapIteratorNext, 2, 1) \
\
/* Harmony weak maps and sets */ \
--- /dev/null
+// 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, []);