Commit 4984224a authored by aandrey@chromium.org's avatar aandrey@chromium.org

Add optional max elements limit for Map/Set mirror iterator preview.

R=yangguo@chromium.org
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#25257}
git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@25257 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ce336605
...@@ -1322,13 +1322,14 @@ inherits(MapMirror, ObjectMirror); ...@@ -1322,13 +1322,14 @@ inherits(MapMirror, ObjectMirror);
* Returns an array of key/value pairs of a map. * Returns an array of key/value pairs of a map.
* This will keep keys alive for WeakMaps. * This will keep keys alive for WeakMaps.
* *
* @param {number=} opt_limit Max elements to return.
* @returns {Array.<Object>} Array of key/value pairs of a map. * @returns {Array.<Object>} Array of key/value pairs of a map.
*/ */
MapMirror.prototype.entries = function() { MapMirror.prototype.entries = function(opt_limit) {
var result = []; var result = [];
if (IS_WEAKMAP(this.value_)) { if (IS_WEAKMAP(this.value_)) {
var entries = %GetWeakMapEntries(this.value_); var entries = %GetWeakMapEntries(this.value_, opt_limit || 0);
for (var i = 0; i < entries.length; i += 2) { for (var i = 0; i < entries.length; i += 2) {
result.push({ result.push({
key: entries[i], key: entries[i],
...@@ -1340,7 +1341,8 @@ MapMirror.prototype.entries = function() { ...@@ -1340,7 +1341,8 @@ MapMirror.prototype.entries = function() {
var iter = %_CallFunction(this.value_, builtins.MapEntries); var iter = %_CallFunction(this.value_, builtins.MapEntries);
var next; var next;
while (!(next = iter.next()).done) { while ((!opt_limit || result.length < opt_limit) &&
!(next = iter.next()).done) {
result.push({ result.push({
key: next.value[0], key: next.value[0],
value: next.value[1] value: next.value[1]
...@@ -1356,10 +1358,11 @@ function SetMirror(value) { ...@@ -1356,10 +1358,11 @@ function SetMirror(value) {
inherits(SetMirror, ObjectMirror); inherits(SetMirror, ObjectMirror);
function IteratorGetValues_(iter, next_function) { function IteratorGetValues_(iter, next_function, opt_limit) {
var result = []; var result = [];
var next; var next;
while (!(next = %_CallFunction(iter, next_function)).done) { while ((!opt_limit || result.length < opt_limit) &&
!(next = %_CallFunction(iter, next_function)).done) {
result.push(next.value); result.push(next.value);
} }
return result; return result;
...@@ -1370,15 +1373,16 @@ function IteratorGetValues_(iter, next_function) { ...@@ -1370,15 +1373,16 @@ function IteratorGetValues_(iter, next_function) {
* 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.
* *
* @param {number=} opt_limit Max elements to return.
* @returns {Array.<Object>} Array of elements of a set. * @returns {Array.<Object>} Array of elements of a set.
*/ */
SetMirror.prototype.values = function() { SetMirror.prototype.values = function(opt_limit) {
if (IS_WEAKSET(this.value_)) { if (IS_WEAKSET(this.value_)) {
return %GetWeakSetValues(this.value_); return %GetWeakSetValues(this.value_, opt_limit || 0);
} }
var iter = %_CallFunction(this.value_, builtins.SetValues); var iter = %_CallFunction(this.value_, builtins.SetValues);
return IteratorGetValues_(iter, builtins.SetIteratorNextJS); return IteratorGetValues_(iter, builtins.SetIteratorNextJS, opt_limit);
}; };
...@@ -1392,15 +1396,18 @@ inherits(IteratorMirror, ObjectMirror); ...@@ -1392,15 +1396,18 @@ inherits(IteratorMirror, ObjectMirror);
* Returns a preview of elements of an iterator. * Returns a preview of elements of an iterator.
* Does not change the backing iterator state. * Does not change the backing iterator state.
* *
* @param {number=} opt_limit Max elements to return.
* @returns {Array.<Object>} Array of elements of an iterator. * @returns {Array.<Object>} Array of elements of an iterator.
*/ */
IteratorMirror.prototype.preview = function() { IteratorMirror.prototype.preview = function(opt_limit) {
if (IS_MAP_ITERATOR(this.value_)) { if (IS_MAP_ITERATOR(this.value_)) {
return IteratorGetValues_(%MapIteratorClone(this.value_), return IteratorGetValues_(%MapIteratorClone(this.value_),
builtins.MapIteratorNextJS); builtins.MapIteratorNextJS,
opt_limit);
} else if (IS_SET_ITERATOR(this.value_)) { } else if (IS_SET_ITERATOR(this.value_)) {
return IteratorGetValues_(%SetIteratorClone(this.value_), return IteratorGetValues_(%SetIteratorClone(this.value_),
builtins.SetIteratorNextJS); builtins.SetIteratorNextJS,
opt_limit);
} }
}; };
......
...@@ -227,23 +227,29 @@ RUNTIME_FUNCTION(Runtime_MapIteratorClone) { ...@@ -227,23 +227,29 @@ RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) { RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
CONVERT_NUMBER_CHECKED(int, max_entries, Int32, args[1]);
RUNTIME_ASSERT(max_entries >= 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
if (max_entries == 0 || max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
Handle<FixedArray> entries = Handle<FixedArray> entries =
isolate->factory()->NewFixedArray(table->NumberOfElements() * 2); isolate->factory()->NewFixedArray(max_entries * 2);
{ {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
int number_of_non_hole_elements = 0; int count = 0;
for (int i = 0; i < table->Capacity(); i++) { for (int i = 0; count / 2 < max_entries && i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate); Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(*key)) { if (table->IsKey(*key)) {
entries->set(number_of_non_hole_elements++, *key); entries->set(count++, *key);
Object* value = table->Lookup(key); Object* value = table->Lookup(key);
entries->set(number_of_non_hole_elements++, value); entries->set(count++, value);
} }
} }
DCHECK_EQ(table->NumberOfElements() * 2, number_of_non_hole_elements); DCHECK_EQ(max_entries * 2, count);
} }
return *isolate->factory()->NewJSArrayWithElements(entries); return *isolate->factory()->NewJSArrayWithElements(entries);
} }
...@@ -346,21 +352,24 @@ RUNTIME_FUNCTION(Runtime_WeakCollectionSet) { ...@@ -346,21 +352,24 @@ RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
RUNTIME_FUNCTION(Runtime_GetWeakSetValues) { RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0); CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
CONVERT_NUMBER_CHECKED(int, max_values, Int32, args[1]);
RUNTIME_ASSERT(max_values >= 0);
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table())); Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
Handle<FixedArray> values = if (max_values == 0 || max_values > table->NumberOfElements()) {
isolate->factory()->NewFixedArray(table->NumberOfElements()); max_values = table->NumberOfElements();
}
Handle<FixedArray> values = isolate->factory()->NewFixedArray(max_values);
{ {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
int number_of_non_hole_elements = 0; int count = 0;
for (int i = 0; i < table->Capacity(); i++) { for (int i = 0; count < max_values && i < table->Capacity(); i++) {
Handle<Object> key(table->KeyAt(i), isolate); Handle<Object> key(table->KeyAt(i), isolate);
if (table->IsKey(*key)) { if (table->IsKey(*key)) values->set(count++, *key);
values->set(number_of_non_hole_elements++, *key);
}
} }
DCHECK_EQ(table->NumberOfElements(), number_of_non_hole_elements); DCHECK_EQ(max_values, count);
} }
return *isolate->factory()->NewJSArrayWithElements(values); return *isolate->factory()->NewJSArrayWithElements(values);
} }
......
...@@ -333,8 +333,8 @@ namespace internal { ...@@ -333,8 +333,8 @@ namespace internal {
F(WeakCollectionDelete, 2, 1) \ F(WeakCollectionDelete, 2, 1) \
F(WeakCollectionSet, 3, 1) \ F(WeakCollectionSet, 3, 1) \
\ \
F(GetWeakMapEntries, 1, 1) \ F(GetWeakMapEntries, 2, 1) \
F(GetWeakSetValues, 1, 1) \ F(GetWeakSetValues, 2, 1) \
\ \
/* Harmony events */ \ /* Harmony events */ \
F(EnqueueMicrotask, 1, 1) \ F(EnqueueMicrotask, 1, 1) \
......
...@@ -51,6 +51,7 @@ map.set(o2, 22); ...@@ -51,6 +51,7 @@ map.set(o2, 22);
map.delete(o1); map.delete(o1);
var mapMirror = debug.MakeMirror(map); var mapMirror = debug.MakeMirror(map);
testMapMirror(mapMirror); testMapMirror(mapMirror);
var entries = mapMirror.entries(); var entries = mapMirror.entries();
assertEquals(1, entries.length); assertEquals(1, entries.length);
assertSame(o2, entries[0].key); assertSame(o2, entries[0].key);
...@@ -59,6 +60,7 @@ map.set(o1, 33); ...@@ -59,6 +60,7 @@ map.set(o1, 33);
map.set(o3, o2); map.set(o3, o2);
map.delete(o2); map.delete(o2);
map.set(undefined, 44); map.set(undefined, 44);
entries = mapMirror.entries(); entries = mapMirror.entries();
assertEquals(3, entries.length); assertEquals(3, entries.length);
assertSame(o1, entries[0].key); assertSame(o1, entries[0].key);
...@@ -68,6 +70,10 @@ assertSame(o2, entries[1].value); ...@@ -68,6 +70,10 @@ assertSame(o2, entries[1].value);
assertEquals(undefined, entries[2].key); assertEquals(undefined, entries[2].key);
assertEquals(44, entries[2].value); assertEquals(44, entries[2].value);
assertEquals(3, mapMirror.entries(0).length);
assertEquals(1, mapMirror.entries(1).length);
assertEquals(2, mapMirror.entries(2).length);
// Test the mirror object for Sets // Test the mirror object for Sets
var set = new Set(); var set = new Set();
set.add(o1); set.add(o1);
...@@ -78,6 +84,7 @@ var setMirror = debug.MakeMirror(set); ...@@ -78,6 +84,7 @@ var setMirror = debug.MakeMirror(set);
testSetMirror(setMirror); testSetMirror(setMirror);
var values = setMirror.values(); var values = setMirror.values();
assertEquals(2, values.length); assertEquals(2, values.length);
assertEquals(1, setMirror.values(1).length);
assertSame(o2, values[0]); assertSame(o2, values[0]);
assertEquals(undefined, values[1]); assertEquals(undefined, values[1]);
...@@ -96,6 +103,8 @@ gc(); ...@@ -96,6 +103,8 @@ gc();
function testWeakMapEntries(weakMapMirror) { function testWeakMapEntries(weakMapMirror) {
var entries = weakMapMirror.entries(); var entries = weakMapMirror.entries();
assertEquals(2, entries.length); assertEquals(2, entries.length);
assertEquals(2, weakMapMirror.entries(0).length);
assertEquals(1, weakMapMirror.entries(1).length);
var found = 0; var found = 0;
for (var i = 0; i < entries.length; i++) { for (var i = 0; i < entries.length; i++) {
if (Object.is(entries[i].key, o1)) { if (Object.is(entries[i].key, o1)) {
...@@ -129,6 +138,8 @@ gc(); ...@@ -129,6 +138,8 @@ gc();
function testWeakSetValues(weakSetMirror) { function testWeakSetValues(weakSetMirror) {
var values = weakSetMirror.values(); var values = weakSetMirror.values();
assertEquals(2, values.length); assertEquals(2, values.length);
assertEquals(2, weakSetMirror.values(0).length);
assertEquals(1, weakSetMirror.values(1).length);
var found = 0; var found = 0;
for (var i = 0; i < values.length; i++) { for (var i = 0; i < values.length; i++) {
if (Object.is(values[i], o1)) { if (Object.is(values[i], o1)) {
......
...@@ -5,18 +5,21 @@ ...@@ -5,18 +5,21 @@
// Flags: --expose-debug-as debug // Flags: --expose-debug-as debug
// Test the mirror object for collection iterators. // Test the mirror object for collection iterators.
function testIteratorMirror(iter, offset, expected) { function testIteratorMirror(iter, offset, expected, opt_limit) {
while (offset-- > 0) iter.next(); while (offset-- > 0) iter.next();
var mirror = debug.MakeMirror(iter); var mirror = debug.MakeMirror(iter);
assertTrue(mirror.isIterator()); assertTrue(mirror.isIterator());
var preview = mirror.preview(); var preview = mirror.preview(opt_limit);
assertArrayEquals(expected, preview); assertArrayEquals(expected, preview);
// Check that iterator has not changed after taking preview. // Check that iterator has not changed after taking preview.
var values = []; var values = [];
for (var i of iter) values.push(i); for (var i of iter) {
if (opt_limit && values.length >= opt_limit) break;
values.push(i);
}
assertArrayEquals(expected, values); assertArrayEquals(expected, values);
} }
...@@ -39,6 +42,11 @@ testIteratorMirror(map.keys(), 2, []); ...@@ -39,6 +42,11 @@ testIteratorMirror(map.keys(), 2, []);
testIteratorMirror(map.values(), 2, []); testIteratorMirror(map.values(), 2, []);
testIteratorMirror(map.entries(), 2, []); testIteratorMirror(map.entries(), 2, []);
// Test with maximum limit.
testIteratorMirror(map.keys(), 0, [41], 1);
testIteratorMirror(map.values(), 0, [42], 1);
testIteratorMirror(map.entries(), 0, [[41, 42]], 1);
var set = new Set(); var set = new Set();
set.add(41); set.add(41);
set.add(42); set.add(42);
...@@ -60,3 +68,8 @@ testIteratorMirror(set.entries(), 3, [[o2, o2]]); ...@@ -60,3 +68,8 @@ testIteratorMirror(set.entries(), 3, [[o2, o2]]);
testIteratorMirror(set.keys(), 5, []); testIteratorMirror(set.keys(), 5, []);
testIteratorMirror(set.values(), 5, []); testIteratorMirror(set.values(), 5, []);
testIteratorMirror(set.entries(), 5, []); testIteratorMirror(set.entries(), 5, []);
// Test with maximum limit.
testIteratorMirror(set.keys(), 1, [42, o1], 2);
testIteratorMirror(set.values(), 1, [42, o1], 2);
testIteratorMirror(set.entries(), 1, [[42, 42], [o1, o1]], 2);
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