v8/test/mjsunit/es6/collection-iterator.js
Benedikt Meurer 1287688ca7 [turbofan] Inline Map and Set iterators into optimized code.
This CL inlines the following builtins into TurboFan

  - %MapIteratorPrototype%.next
  - %SetIteratorPrototype%.next

following the design that we are using for Array iteration already
(different instance types for the different kinds of iterators). Details
can be found in the relevant design document at:

  https://docs.google.com/document/d/13z1fvRVpe_oEroplXEEX0a3WK94fhXorHjcOMsDmR-8

The key to great performance here is to ensure that the inlined code
allows escape analysis and scalar replacement of aggregates to remove
the allocations for the iterator itself as well as the iterator results
and potential key/value arrays in the simple case of a for-of loop (and
by extension also in other constructs that reduce to for-of loops
internally), i.e.:

  const s = new Set;
  // ... do something with s
  for (const x of s) {
    // ...
  }

Here the for-of loop shouldn't perform any allocations of helper
objects.

Drive-by-fix: Replace the ExistsJSMapWithness in JSBuiltinReducer with a more
general HasInstanceTypeWitness, similar to what's in JSCallReducer. Also
migrate the {Map,Set}.prototype.size getter inlining to the
JSBuiltinReducer, so that everything is in a single place.

R=jgruber@chromium.org

Bug: v8:6344, v8:6571, chromium:740122
Change-Id: I09cb506fe26ed3e10d7dcb2f95ec4415e639582d
Reviewed-on: https://chromium-review.googlesource.com/570159
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46655}
2017-07-14 07:02:00 +00:00

262 lines
7.3 KiB
JavaScript

// 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: --allow-natives-syntax
function test(f) {
f();
f();
%OptimizeFunctionOnNextCall(f);
f();
}
test(function TestSetIterator() {
var s = new Set;
var iter = s.values();
assertEquals('Set Iterator', %_ClassOf(iter));
var SetIteratorPrototype = iter.__proto__;
assertFalse(SetIteratorPrototype.hasOwnProperty('constructor'));
assertEquals(SetIteratorPrototype.__proto__, Object.prototype);
var propertyNames = Object.getOwnPropertyNames(SetIteratorPrototype);
assertArrayEquals(['next'], propertyNames);
assertEquals(new Set().values().__proto__, SetIteratorPrototype);
assertEquals(new Set().entries().__proto__, SetIteratorPrototype);
assertEquals("[object Set Iterator]",
Object.prototype.toString.call(iter));
assertEquals("Set Iterator", SetIteratorPrototype[Symbol.toStringTag]);
var desc = Object.getOwnPropertyDescriptor(
SetIteratorPrototype, Symbol.toStringTag);
assertTrue(desc.configurable);
assertFalse(desc.writable);
assertEquals("Set Iterator", desc.value);
});
test(function TestSetIteratorValues() {
var s = new Set;
s.add(1);
s.add(2);
s.add(3);
var iter = s.values();
assertEquals({value: 1, done: false}, iter.next());
assertEquals({value: 2, done: false}, iter.next());
assertEquals({value: 3, done: false}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestSetIteratorKeys() {
assertEquals(Set.prototype.keys, Set.prototype.values);
});
test(function TestSetIteratorEntries() {
var s = new Set;
s.add(1);
s.add(2);
s.add(3);
var iter = s.entries();
assertEquals({value: [1, 1], done: false}, iter.next());
assertEquals({value: [2, 2], done: false}, iter.next());
assertEquals({value: [3, 3], done: false}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestSetIteratorMutations() {
var s = new Set;
s.add(1);
var iter = s.values();
assertEquals({value: 1, done: false}, iter.next());
s.add(2);
s.add(3);
s.add(4);
s.add(5);
assertEquals({value: 2, done: false}, iter.next());
s.delete(3);
assertEquals({value: 4, done: false}, iter.next());
s.delete(5);
assertEquals({value: undefined, done: true}, iter.next());
s.add(4);
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestSetIteratorMutations2() {
var s = new Set;
s.add(1);
s.add(2);
var i = s.values();
assertEquals({value: 1, done: false}, i.next());
s.delete(2);
s.delete(1);
s.add(2);
assertEquals({value: 2, done: false}, i.next());
assertEquals({value: undefined, done: true}, i.next());
});
test(function TestSetIteratorMutations3() {
var s = new Set;
s.add(1);
s.add(2);
var i = s.values();
assertEquals({value: 1, done: false}, i.next());
s.delete(2);
s.delete(1);
for (var x = 2; x < 500; ++x) s.add(x);
for (var x = 2; x < 500; ++x) s.delete(x);
for (var x = 2; x < 1000; ++x) s.add(x);
assertEquals({value: 2, done: false}, i.next());
for (var x = 1001; x < 2000; ++x) s.add(x);
s.delete(3);
for (var x = 6; x < 2000; ++x) s.delete(x);
assertEquals({value: 4, done: false}, i.next());
s.delete(5);
assertEquals({value: undefined, done: true}, i.next());
s.add(4);
assertEquals({value: undefined, done: true}, i.next());
});
test(function TestSetInvalidReceiver() {
assertThrows(function() {
Set.prototype.values.call({});
}, TypeError);
assertThrows(function() {
Set.prototype.entries.call({});
}, TypeError);
});
test(function TestSetIteratorInvalidReceiver() {
var iter = new Set().values();
assertThrows(function() {
iter.next.call({});
});
});
test(function TestSetIteratorSymbol() {
assertEquals(Set.prototype[Symbol.iterator], Set.prototype.values);
assertTrue(Set.prototype.hasOwnProperty(Symbol.iterator));
assertFalse(Set.prototype.propertyIsEnumerable(Symbol.iterator));
var iter = new Set().values();
assertEquals(iter, iter[Symbol.iterator]());
assertEquals(iter[Symbol.iterator].name, '[Symbol.iterator]');
});
test(function TestMapIterator() {
var m = new Map;
var iter = m.values();
assertEquals('Map Iterator', %_ClassOf(iter));
var MapIteratorPrototype = iter.__proto__;
assertFalse(MapIteratorPrototype.hasOwnProperty('constructor'));
assertEquals(MapIteratorPrototype.__proto__, Object.prototype);
var propertyNames = Object.getOwnPropertyNames(MapIteratorPrototype);
assertArrayEquals(['next'], propertyNames);
assertEquals(new Map().values().__proto__, MapIteratorPrototype);
assertEquals(new Map().keys().__proto__, MapIteratorPrototype);
assertEquals(new Map().entries().__proto__, MapIteratorPrototype);
assertEquals("[object Map Iterator]",
Object.prototype.toString.call(iter));
assertEquals("Map Iterator", MapIteratorPrototype[Symbol.toStringTag]);
var desc = Object.getOwnPropertyDescriptor(
MapIteratorPrototype, Symbol.toStringTag);
assertTrue(desc.configurable);
assertFalse(desc.writable);
assertEquals("Map Iterator", desc.value);
});
test(function TestMapIteratorValues() {
var m = new Map;
m.set(1, 11);
m.set(2, 22);
m.set(3, 33);
var iter = m.values();
assertEquals({value: 11, done: false}, iter.next());
assertEquals({value: 22, done: false}, iter.next());
assertEquals({value: 33, done: false}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestMapIteratorKeys() {
var m = new Map;
m.set(1, 11);
m.set(2, 22);
m.set(3, 33);
var iter = m.keys();
assertEquals({value: 1, done: false}, iter.next());
assertEquals({value: 2, done: false}, iter.next());
assertEquals({value: 3, done: false}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestMapIteratorEntries() {
var m = new Map;
m.set(1, 11);
m.set(2, 22);
m.set(3, 33);
var iter = m.entries();
assertEquals({value: [1, 11], done: false}, iter.next());
assertEquals({value: [2, 22], done: false}, iter.next());
assertEquals({value: [3, 33], done: false}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
assertEquals({value: undefined, done: true}, iter.next());
});
test(function TestMapInvalidReceiver() {
assertThrows(function() {
Map.prototype.values.call({});
}, TypeError);
assertThrows(function() {
Map.prototype.keys.call({});
}, TypeError);
assertThrows(function() {
Map.prototype.entries.call({});
}, TypeError);
});
test(function TestMapIteratorInvalidReceiver() {
var iter = new Map().values();
assertThrows(function() {
iter.next.call({});
}, TypeError);
});
test(function TestMapIteratorSymbol() {
assertEquals(Map.prototype[Symbol.iterator], Map.prototype.entries);
assertTrue(Map.prototype.hasOwnProperty(Symbol.iterator));
assertFalse(Map.prototype.propertyIsEnumerable(Symbol.iterator));
var iter = new Map().values();
assertEquals(iter, iter[Symbol.iterator]());
assertEquals(iter[Symbol.iterator].name, '[Symbol.iterator]');
});