Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Unified Diff: src/compiler/js-builtin-reducer.cc

Issue 2484003002: [builtins] implement JSBuiltinReducer for ArrayIteratorNext() (Closed)
Patch Set: CheckIf() for ArrayBufferWasNeutered() rather than a branch, which hopefully can be eliminated, and… Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/compiler/js-builtin-reducer.cc
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
index 8bc03fae6239b850a901aab90cc41bf09ee30983..29ae91b00043965b64cb1fda2a1abe395d20da63 100644
--- a/src/compiler/js-builtin-reducer.cc
+++ b/src/compiler/js-builtin-reducer.cc
@@ -175,8 +175,639 @@ bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) {
!IsReadOnlyLengthDescriptor(receiver_map);
}
+bool CanInlineJSArrayIteration(Handle<Map> receiver_map) {
+ Isolate* const isolate = receiver_map->GetIsolate();
+ // Ensure that the [[Prototype]] is actually an exotic Array
+ if (!receiver_map->prototype()->IsJSArray()) return false;
+
+ // Don't inline JSArrays with slow elements of any kind
+ if (!IsFastElementsKind(receiver_map->elements_kind())) return false;
+
+ // If the receiver map has packed elements, no need to check the prototype.
+ // This requires a MapCheck where this is used.
+ if (IsFastHoleyElementsKind(receiver_map->elements_kind())) return true;
Benedikt Meurer 2016/11/09 05:37:05 Return true if non-holey.
caitp 2016/11/09 17:40:16 oop, good catch.
+
+ Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
+ isolate);
+ // Ensure all prototypes of the {receiver} are stable.
+ for (PrototypeIterator it(isolate, receiver_prototype, kStartAtReceiver);
+ !it.IsAtEnd(); it.Advance()) {
+ Handle<JSReceiver> current = PrototypeIterator::GetCurrent<JSReceiver>(it);
+ if (!current->map()->is_stable()) return false;
+ }
+
+ // For holey Arrays, ensure that the array_protector cell is valid (must be
+ // a CompilationDependency), and the JSArray prototype has not been altered.
+ return receiver_map->instance_type() == JS_ARRAY_TYPE &&
+ (!receiver_map->is_dictionary_map() || receiver_map->is_stable()) &&
+ isolate->IsFastArrayConstructorPrototypeChainIntact() &&
+ isolate->IsAnyInitialArrayPrototype(receiver_prototype);
+}
+
} // namespace
+Reduction JSBuiltinReducer::ReduceArrayIterator(Node* node,
+ IterationKind kind) {
+ Handle<Map> receiver_map;
+ if (GetMapWitness(node).ToHandle(&receiver_map)) {
+ return ReduceArrayIterator(receiver_map, node, kind, false);
+ }
+ return NoChange();
+}
+
+Reduction JSBuiltinReducer::ReduceTypedArrayIterator(Node* node,
+ IterationKind kind) {
+ Handle<Map> receiver_map;
+ if (GetMapWitness(node).ToHandle(&receiver_map) &&
+ receiver_map->instance_type() == JS_TYPED_ARRAY_TYPE) {
+ return ReduceArrayIterator(receiver_map, node, kind, true);
+ }
+ return NoChange();
+}
+
+Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
+ Node* node, IterationKind kind,
+ bool for_typed_array) {
+ Node* receiver = NodeProperties::GetValueInput(node, 1);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+
+ if (for_typed_array) {
+ // For JSTypedArray iterator methods, deopt if the buffer is neutered
+ DCHECK_EQ(receiver_map->instance_type(), JS_TYPED_ARRAY_TYPE);
+ Node* buffer = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
+ receiver, effect, control);
+
+ Node* check = effect = graph()->NewNode(
+ simplified()->ArrayBufferWasNeutered(), buffer, effect, control);
+ effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control);
+ }
+
+ int map_index = -1;
+ Node* object_map = jsgraph()->UndefinedConstant();
+ switch (receiver_map->instance_type()) {
+ case JS_ARRAY_TYPE:
+ if (kind == IterationKind::kKeys) {
+ map_index = Context::FAST_ARRAY_KEY_ITERATOR_MAP_INDEX;
+ } else {
+ map_index = kind == IterationKind::kValues
+ ? Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX
+ : Context::FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
+
+ if (CanInlineJSArrayIteration(receiver_map)) {
+ // Use `generic` elements for holey arrays if there may be elements
+ // on the prototype chain.
+ map_index += static_cast<int>(receiver_map->elements_kind());
+ object_map = jsgraph()->Constant(receiver_map);
+ if (IsFastHoleyElementsKind(receiver_map->elements_kind())) {
+ Handle<JSObject> initial_array_prototype(
+ native_context()->initial_array_prototype(), isolate());
+ dependencies()->AssumePrototypeMapsStable(receiver_map,
+ initial_array_prototype);
+ }
+ } else {
+ map_index += (Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX -
+ Context::FAST_SMI_ARRAY_VALUE_ITERATOR_MAP_INDEX);
+ }
+ }
+ break;
+ case JS_TYPED_ARRAY_TYPE:
+ if (kind == IterationKind::kKeys) {
+ map_index = Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX;
+ } else {
+ DCHECK_GE(receiver_map->elements_kind(), UINT8_ELEMENTS);
+ DCHECK_LE(receiver_map->elements_kind(), UINT8_CLAMPED_ELEMENTS);
+ map_index = (kind == IterationKind::kValues
+ ? Context::UINT8_ARRAY_VALUE_ITERATOR_MAP_INDEX
+ : Context::UINT8_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX) +
+ (receiver_map->elements_kind() - UINT8_ELEMENTS);
+ }
+ break;
+ default:
+ if (kind == IterationKind::kKeys) {
+ map_index = Context::GENERIC_ARRAY_KEY_ITERATOR_MAP_INDEX;
+ } else if (kind == IterationKind::kValues) {
+ map_index = Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX;
+ } else {
+ map_index = Context::GENERIC_ARRAY_KEY_VALUE_ITERATOR_MAP_INDEX;
+ }
+ break;
+ }
+
+ DCHECK_GE(map_index, Context::TYPED_ARRAY_KEY_ITERATOR_MAP_INDEX);
+ DCHECK_LE(map_index, Context::GENERIC_ARRAY_VALUE_ITERATOR_MAP_INDEX);
+
+ Handle<Map> map(Map::cast(native_context()->get(map_index)), isolate());
+
+ // allocate new iterator
+ effect = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable), effect);
+ Node* value = effect = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(JSArrayIterator::kSize), effect, control);
+ effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
+ value, jsgraph()->Constant(map), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectProperties()), value,
+ jsgraph()->EmptyFixedArrayConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectElements()), value,
+ jsgraph()->EmptyFixedArrayConstant(), effect, control);
+
+ // attach the iterator to this object
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
+ value, receiver, effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex()), value,
+ jsgraph()->ZeroConstant(), effect, control);
+ effect = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObjectMap()),
+ value, object_map, effect, control);
+
+ value = effect = graph()->NewNode(common()->FinishRegion(), value, effect);
+
+ // replace it
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+}
+
+Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
+ Handle<Map> iterator_map, Node* node, IterationKind kind) {
+ Node* iterator = NodeProperties::GetValueInput(node, 1);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+
+ if (kind != IterationKind::kKeys && !isolate()->CanInlineArrayIterator()) {
+ // Avoid deopt loops for non-key iteration if the array_iterator_protector
+ // cell has been invalidated.
+ return NoChange();
+ }
+
+ ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
+ iterator_map->instance_type());
+
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
+ return NoChange();
+ } else {
+ Handle<JSObject> initial_array_prototype(
+ native_context()->initial_array_prototype(), isolate());
+ dependencies()->AssumePropertyCell(factory()->array_protector());
+ }
+ }
+
+ Node* array = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
+ iterator, effect, control);
+ Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
+ jsgraph()->UndefinedConstant());
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
+
+ Node* vdone_false0;
+ Node* vfalse0;
+ Node* efalse0 = effect;
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ {
+ // iterator.[[IteratedObject]] !== undefined, continue iterating.
+ Node* index = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
+ JS_ARRAY_TYPE, elements_kind)),
+ iterator, efalse0, if_false0);
+
+ Node* length = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
+ array, efalse0, if_false0);
+ Node* check1 =
+ graph()->NewNode(simplified()->NumberLessThan(), index, length);
+ Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+ check1, if_false0);
+
+ Node* vdone_true1;
+ Node* vtrue1;
+ Node* etrue1 = efalse0;
+ Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
+ {
+ // iterator.[[NextIndex]] < array.length, continue iterating
+ vdone_true1 = jsgraph()->FalseConstant();
+ if (kind == IterationKind::kKeys) {
+ vtrue1 = index;
+ } else {
+ // For value/entry iteration, first step is a mapcheck to ensure
+ // inlining is still valid.
+ Node* orig_map = etrue1 =
+ graph()->NewNode(simplified()->LoadField(
+ AccessBuilder::ForJSArrayIteratorObjectMap()),
+ iterator, etrue1, if_true1);
+ etrue1 = graph()->NewNode(simplified()->CheckMaps(1), array, orig_map,
+ etrue1, if_true1);
+ }
+
+ Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
+ jsgraph()->OneConstant());
+ next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
+
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
+ JS_ARRAY_TYPE, elements_kind)),
+ iterator, next_index, etrue1, if_true1);
+
+ if (kind != IterationKind::kKeys) {
+ Node* elements = etrue1 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
+ array, etrue1, if_true1);
+ Node* value = etrue1 = graph()->NewNode(
+ simplified()->LoadElement(
+ AccessBuilder::ForFixedArrayElement(elements_kind)),
+ elements, index, etrue1, if_true1);
+
+ // Convert hole to undefined if needed.
+ if (elements_kind == FAST_HOLEY_ELEMENTS ||
+ elements_kind == FAST_HOLEY_SMI_ELEMENTS) {
+ value = graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(),
+ value);
+ } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) {
+ CheckFloat64HoleMode mode = CheckFloat64HoleMode::kAllowReturnHole;
+ // Check if we are allowed to return the hole directly.
+ value = etrue1 = graph()->NewNode(
+ simplified()->CheckFloat64Hole(mode), value, etrue1, if_true1);
+ }
+
+ if (kind == IterationKind::kEntries) {
+ // Allocate elements for key/value pair
+ etrue1 = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable),
+ etrue1);
+ Node* elements = etrue1 = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(FixedArray::SizeFor(2)), etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), elements,
+ jsgraph()->Constant(isolate()->factory()->fixed_array_map()),
+ etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
+ elements, jsgraph()->Constant(2));
+ etrue1 = graph()->NewNode(
+ simplified()->StoreElement(
+ AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
+ elements, jsgraph()->Constant(0), index, etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreElement(
+ AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
+ elements, jsgraph()->Constant(1), value, etrue1, if_true1);
+ elements = etrue1 =
+ graph()->NewNode(common()->FinishRegion(), elements, etrue1);
+
+ // Allocate JSArray for key/value pair
+ etrue1 = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable),
+ etrue1);
+ Node* entry = etrue1 = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(JSArray::kSize), etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), entry,
+ jsgraph()->Constant(
+ handle(native_context()->js_array_fast_elements_map_index())),
+ etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectProperties()),
+ entry, jsgraph()->EmptyFixedArrayConstant(), etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectElements()),
+ entry, elements, etrue1, if_true1);
+ etrue1 = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForJSArrayLength(elements_kind)),
+ entry, jsgraph()->Constant(2), etrue1, if_true1);
+ entry = etrue1 =
+ graph()->NewNode(common()->FinishRegion(), entry, etrue1);
+ vtrue1 = entry;
+ } else {
+ DCHECK_EQ(kind, IterationKind::kValues);
+ vtrue1 = value;
+ }
+ }
+ }
+
+ Node* vdone_false1;
+ Node* vfalse1;
+ Node* efalse1 = efalse0;
+ Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
+ {
+ // iterator.[[NextIndex]] >= array.length, stop iterating.
+ vdone_false1 = jsgraph()->TrueConstant();
+ vfalse1 = jsgraph()->UndefinedConstant();
+ efalse1 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
+ iterator, vfalse1, efalse1, if_false1);
+ }
+
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
+ efalse0 =
+ graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
+ vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vtrue1, vfalse1, if_false0);
+ vdone_false0 =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vdone_true1, vdone_false1, if_false0);
+ }
+
+ Node* vdone_true0;
+ Node* vtrue0;
+ Node* etrue0 = effect;
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ {
+ // iterator.[[IteratedObject]] === undefined, the iterator is done.
+ vdone_true0 = jsgraph()->TrueConstant();
+ vtrue0 = jsgraph()->UndefinedConstant();
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
+ effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
+ Node* value =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vfalse0, vtrue0, control);
+ Node* done =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vdone_false0, vdone_true0, control);
+
+ // Create IteratorResult object.
+ value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
+ value, done, context, effect);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+}
+
+Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
+ Handle<Map> iterator_map, Node* node, IterationKind kind) {
+ Node* iterator = NodeProperties::GetValueInput(node, 1);
+ Node* effect = NodeProperties::GetEffectInput(node);
+ Node* control = NodeProperties::GetControlInput(node);
+ Node* context = NodeProperties::GetContextInput(node);
+
+ ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
+ iterator_map->instance_type());
+
+ Node* array = effect = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
+ iterator, effect, control);
+ Node* check0 = graph()->NewNode(simplified()->ReferenceEqual(), array,
+ jsgraph()->UndefinedConstant());
+ Node* branch0 =
+ graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);
+
+ Node* vdone_false0;
+ Node* vfalse0;
+ Node* efalse0 = effect;
+ Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
+ {
+ // iterator.[[IteratedObject]] !== undefined, continue iterating.
+ Node* index = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayIteratorIndex(
+ JS_TYPED_ARRAY_TYPE, elements_kind)),
+ iterator, efalse0, if_false0);
+
+ // typedarray.[[ViewedArrayBuffer]]
+ Node* buffer = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()),
+ array, efalse0, if_false0);
+
+ Node* check1 = efalse0 = graph()->NewNode(
+ simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
+ efalse0 =
+ graph()->NewNode(simplified()->CheckIf(), check1, efalse0, if_false0);
+
+ Node* length = efalse0 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), array,
+ efalse0, if_false0);
+
+ Node* check2 =
+ graph()->NewNode(simplified()->NumberLessThan(), index, length);
+ Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
+ check2, if_false0);
+
+ Node* vdone_true2;
+ Node* vtrue2;
+ Node* etrue2 = efalse0;
+ Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
+ {
+ // iterator.[[NextIndex]] < array.length, continue iterating
+ vdone_true2 = jsgraph()->FalseConstant();
+ if (kind == IterationKind::kKeys) {
+ vtrue2 = index;
+ }
+
+ Node* next_index = graph()->NewNode(simplified()->NumberAdd(), index,
+ jsgraph()->OneConstant());
+ next_index = graph()->NewNode(simplified()->NumberToUint32(), next_index);
+
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorIndex(
+ JS_TYPED_ARRAY_TYPE, elements_kind)),
+ iterator, next_index, etrue2, if_true2);
+
+ if (kind != IterationKind::kKeys) {
+ Node* elements = etrue2 = graph()->NewNode(
+ simplified()->LoadField(AccessBuilder::ForJSObjectElements()),
+ array, etrue2, if_true2);
+ Node* base_ptr = etrue2 = graph()->NewNode(
+ simplified()->LoadField(
+ AccessBuilder::ForFixedTypedArrayBaseBasePointer()),
+ elements, etrue2, if_true2);
+ Node* external_ptr = etrue2 = graph()->NewNode(
+ simplified()->LoadField(
+ AccessBuilder::ForFixedTypedArrayBaseExternalPointer()),
+ elements, etrue2, if_true2);
+
+ ExternalArrayType array_type = kExternalInt8Array;
+ switch (elements_kind) {
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+ case TYPE##_ELEMENTS: \
+ array_type = kExternal##Type##Array;
+ TYPED_ARRAYS(TYPED_ARRAY_CASE)
+ default:
+ UNREACHABLE();
+#undef TYPED_ARRAY_CASE
+ }
+
+ Node* value = etrue2 =
+ graph()->NewNode(simplified()->LoadTypedElement(array_type), buffer,
+ base_ptr, external_ptr, index, etrue2, if_true2);
+
+ if (kind == IterationKind::kEntries) {
+ // Allocate elements for key/value pair
Camillo Bruni 2016/11/09 12:03:49 Could you somehow reuse the following snippet, thi
caitp 2016/11/09 17:40:16 Ah, I've created an opcode for this to avoid the d
+ etrue2 = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable),
+ etrue2);
+ Node* elements = etrue2 = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(FixedArray::SizeFor(2)), etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), elements,
+ jsgraph()->Constant(isolate()->factory()->fixed_array_map()),
+ etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForFixedArrayLength()),
+ elements, jsgraph()->Constant(2));
+ etrue2 = graph()->NewNode(
+ simplified()->StoreElement(
+ AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
+ elements, jsgraph()->Constant(0), index, etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreElement(
+ AccessBuilder::ForFixedArrayElement(FAST_ELEMENTS)),
+ elements, jsgraph()->Constant(1), value, etrue2, if_true2);
+ elements = etrue2 =
+ graph()->NewNode(common()->FinishRegion(), elements, etrue2);
+
+ // Allocate JSArray for key/value pair
+ etrue2 = graph()->NewNode(
+ common()->BeginRegion(RegionObservability::kNotObservable),
+ etrue2);
+ Node* entry = etrue2 = graph()->NewNode(
+ simplified()->Allocate(NOT_TENURED),
+ jsgraph()->Constant(JSArray::kSize), etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForMap()), entry,
+ jsgraph()->Constant(
+ handle(native_context()->js_array_fast_elements_map_index())),
+ etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectProperties()),
+ entry, jsgraph()->EmptyFixedArrayConstant(), etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSObjectElements()),
+ entry, elements, etrue2, if_true2);
+ etrue2 = graph()->NewNode(
+ simplified()->StoreField(
+ AccessBuilder::ForJSArrayLength(elements_kind)),
+ entry, jsgraph()->Constant(2), etrue2, if_true2);
+ entry = etrue2 =
+ graph()->NewNode(common()->FinishRegion(), entry, etrue2);
+ vtrue2 = entry;
+ } else {
+ DCHECK(kind == IterationKind::kValues);
+ vtrue2 = value;
+ }
+ }
+ }
+
+ Node* vdone_false2;
+ Node* vfalse2;
+ Node* efalse2 = efalse0;
+ Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
+ {
+ // iterator.[[NextIndex]] >= array.length, stop iterating.
+ vdone_false2 = jsgraph()->TrueConstant();
+ vfalse2 = jsgraph()->UndefinedConstant();
+ efalse2 = graph()->NewNode(
+ simplified()->StoreField(AccessBuilder::ForJSArrayIteratorObject()),
+ iterator, vfalse2, efalse2, if_false2);
+ }
+
+ if_false0 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
+ efalse0 =
+ graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_false0);
+ vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vtrue2, vfalse2, if_false0);
+ vdone_false0 =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vdone_true2, vdone_false2, if_false0);
+ }
+
+ Node* vdone_true0;
+ Node* vtrue0;
+ Node* etrue0 = effect;
+ Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
+ {
+ // iterator.[[IteratedObject]] === undefined, the iterator is done.
+ vdone_true0 = jsgraph()->TrueConstant();
+ vtrue0 = jsgraph()->UndefinedConstant();
+ }
+
+ control = graph()->NewNode(common()->Merge(2), if_false0, if_true0);
+ effect = graph()->NewNode(common()->EffectPhi(2), efalse0, etrue0, control);
+ Node* value =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vfalse0, vtrue0, control);
+ Node* done =
+ graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
+ vdone_false0, vdone_true0, control);
+
+ // Create IteratorResult object.
+ value = effect = graph()->NewNode(javascript()->CreateIterResultObject(),
+ value, done, context, effect);
+ ReplaceWithValue(node, value, effect, control);
+ return Replace(value);
+}
+
+Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
+ Handle<Map> receiver_map;
+ if (GetMapWitness(node).ToHandle(&receiver_map)) {
+ switch (receiver_map->instance_type()) {
+ case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(receiver_map, node,
+ IterationKind::kKeys);
+
+ case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(receiver_map, node,
+ IterationKind::kKeys);
+
+ case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(receiver_map, node,
+ IterationKind::kEntries);
+
+ case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(receiver_map, node,
+ IterationKind::kEntries);
+
+ case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
+ return ReduceTypedArrayIteratorNext(receiver_map, node,
+ IterationKind::kValues);
+
+ case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
+ case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
+ return ReduceFastArrayIteratorNext(receiver_map, node,
+ IterationKind::kValues);
+
+ default:
+ // Slow array iterators are not reduced
+ return NoChange();
+ }
+ }
+ return NoChange();
+}
+
// ES6 section 22.1.3.17 Array.prototype.pop ( )
Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) {
Handle<Map> receiver_map;
@@ -1260,6 +1891,14 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
// Dispatch according to the BuiltinFunctionId if present.
if (!r.HasBuiltinFunctionId()) return NoChange();
switch (r.GetBuiltinFunctionId()) {
+ case kArrayEntries:
+ return ReduceArrayIterator(node, IterationKind::kEntries);
+ case kArrayKeys:
+ return ReduceArrayIterator(node, IterationKind::kKeys);
+ case kArrayValues:
+ return ReduceArrayIterator(node, IterationKind::kValues);
+ case kArrayIteratorNext:
+ return ReduceArrayIteratorNext(node);
case kArrayPop:
return ReduceArrayPop(node);
case kArrayPush:
@@ -1416,6 +2055,12 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kTypedArrayLength:
return ReduceArrayBufferViewAccessor(
node, JS_TYPED_ARRAY_TYPE, AccessBuilder::ForJSTypedArrayLength());
+ case kTypedArrayEntries:
+ return ReduceTypedArrayIterator(node, IterationKind::kEntries);
+ case kTypedArrayKeys:
+ return ReduceTypedArrayIterator(node, IterationKind::kKeys);
+ case kTypedArrayValues:
+ return ReduceTypedArrayIterator(node, IterationKind::kValues);
default:
break;
}

Powered by Google App Engine
This is Rietveld 408576698