1287688ca7
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}
262 lines
7.3 KiB
JavaScript
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]');
|
|
});
|