5 #include "src/compiler/load-elimination.h" 7 #include "src/compiler/common-operator.h" 8 #include "src/compiler/js-graph.h" 9 #include "src/compiler/node-properties.h" 10 #include "src/compiler/simplified-operator.h" 11 #include "src/heap/factory.h" 12 #include "src/objects-inl.h" 20 bool IsRename(Node* node) {
21 switch (node->opcode()) {
22 case IrOpcode::kCheckHeapObject:
23 case IrOpcode::kFinishRegion:
24 case IrOpcode::kTypeGuard:
25 return !node->IsDead();
31 Node* ResolveRenames(Node* node) {
32 while (IsRename(node)) {
33 node = node->InputAt(0);
38 bool MayAlias(Node* a, Node* b) {
40 if (!NodeProperties::GetType(a).Maybe(NodeProperties::GetType(b))) {
42 }
else if (IsRename(b)) {
43 return MayAlias(a, b->InputAt(0));
44 }
else if (IsRename(a)) {
45 return MayAlias(a->InputAt(0), b);
46 }
else if (b->opcode() == IrOpcode::kAllocate) {
47 switch (a->opcode()) {
48 case IrOpcode::kAllocate:
49 case IrOpcode::kHeapConstant:
50 case IrOpcode::kParameter:
55 }
else if (a->opcode() == IrOpcode::kAllocate) {
56 switch (b->opcode()) {
57 case IrOpcode::kHeapConstant:
58 case IrOpcode::kParameter:
68 bool MustAlias(Node* a, Node* b) {
69 return ResolveRenames(a) == ResolveRenames(b);
74 Reduction LoadElimination::Reduce(Node* node) {
75 if (FLAG_trace_turbo_load_elimination) {
76 if (node->op()->EffectInputCount() > 0) {
77 PrintF(
" visit #%d:%s", node->id(), node->op()->mnemonic());
78 if (node->op()->ValueInputCount() > 0) {
80 for (
int i = 0;
i < node->op()->ValueInputCount(); ++
i) {
81 if (
i > 0) PrintF(
", ");
82 Node*
const value = NodeProperties::GetValueInput(node,
i);
83 PrintF(
"#%d:%s", value->id(), value->op()->mnemonic());
88 for (
int i = 0;
i < node->op()->EffectInputCount(); ++
i) {
89 Node*
const effect = NodeProperties::GetEffectInput(node,
i);
90 if (AbstractState
const*
const state = node_states_.Get(effect)) {
91 PrintF(
" state[%i]: #%d:%s\n",
i, effect->id(),
92 effect->op()->mnemonic());
95 PrintF(
" no state[%i]: #%d:%s\n",
i, effect->id(),
96 effect->op()->mnemonic());
101 switch (node->opcode()) {
102 case IrOpcode::kMapGuard:
103 return ReduceMapGuard(node);
104 case IrOpcode::kCheckMaps:
105 return ReduceCheckMaps(node);
106 case IrOpcode::kCompareMaps:
107 return ReduceCompareMaps(node);
108 case IrOpcode::kEnsureWritableFastElements:
109 return ReduceEnsureWritableFastElements(node);
110 case IrOpcode::kMaybeGrowFastElements:
111 return ReduceMaybeGrowFastElements(node);
112 case IrOpcode::kTransitionElementsKind:
113 return ReduceTransitionElementsKind(node);
114 case IrOpcode::kLoadField:
115 return ReduceLoadField(node);
116 case IrOpcode::kStoreField:
117 return ReduceStoreField(node);
118 case IrOpcode::kLoadElement:
119 return ReduceLoadElement(node);
120 case IrOpcode::kStoreElement:
121 return ReduceStoreElement(node);
122 case IrOpcode::kTransitionAndStoreElement:
123 return ReduceTransitionAndStoreElement(node);
124 case IrOpcode::kStoreTypedElement:
125 return ReduceStoreTypedElement(node);
126 case IrOpcode::kEffectPhi:
127 return ReduceEffectPhi(node);
128 case IrOpcode::kDead:
130 case IrOpcode::kStart:
131 return ReduceStart(node);
133 return ReduceOtherNode(node);
140 bool IsCompatible(MachineRepresentation r1, MachineRepresentation r2) {
141 if (r1 == r2)
return true;
142 return IsAnyTagged(r1) && IsAnyTagged(r2);
147 Node* LoadElimination::AbstractElements::Lookup(
148 Node*
object, Node* index, MachineRepresentation representation)
const {
149 for (Element
const element : elements_) {
150 if (element.object ==
nullptr)
continue;
151 DCHECK_NOT_NULL(element.index);
152 DCHECK_NOT_NULL(element.value);
153 if (MustAlias(
object, element.object) && MustAlias(index, element.index) &&
154 IsCompatible(representation, element.representation)) {
155 return element.value;
161 LoadElimination::AbstractElements
const*
162 LoadElimination::AbstractElements::Kill(Node*
object, Node* index,
164 for (Element
const element : this->elements_) {
165 if (element.object ==
nullptr)
continue;
166 if (MayAlias(
object, element.object)) {
167 AbstractElements* that =
new (zone) AbstractElements(zone);
168 for (Element
const element : this->elements_) {
169 if (element.object ==
nullptr)
continue;
170 DCHECK_NOT_NULL(element.index);
171 DCHECK_NOT_NULL(element.value);
172 if (!MayAlias(
object, element.object) ||
173 !NodeProperties::GetType(index).Maybe(
174 NodeProperties::GetType(element.index))) {
175 that->elements_[that->next_index_++] = element;
178 that->next_index_ %= arraysize(elements_);
185 bool LoadElimination::AbstractElements::Equals(
186 AbstractElements
const* that)
const {
187 if (
this == that)
return true;
188 for (
size_t i = 0;
i < arraysize(elements_); ++
i) {
189 Element this_element = this->elements_[
i];
190 if (this_element.object ==
nullptr)
continue;
191 for (
size_t j = 0;; ++j) {
192 if (j == arraysize(elements_))
return false;
193 Element that_element = that->elements_[j];
194 if (this_element.object == that_element.object &&
195 this_element.index == that_element.index &&
196 this_element.value == that_element.value) {
201 for (
size_t i = 0;
i < arraysize(elements_); ++
i) {
202 Element that_element = that->elements_[
i];
203 if (that_element.object ==
nullptr)
continue;
204 for (
size_t j = 0;; ++j) {
205 if (j == arraysize(elements_))
return false;
206 Element this_element = this->elements_[j];
207 if (that_element.object == this_element.object &&
208 that_element.index == this_element.index &&
209 that_element.value == this_element.value) {
217 LoadElimination::AbstractElements
const*
218 LoadElimination::AbstractElements::Merge(AbstractElements
const* that,
220 if (this->Equals(that))
return this;
221 AbstractElements* copy =
new (zone) AbstractElements(zone);
222 for (Element
const this_element : this->elements_) {
223 if (this_element.object ==
nullptr)
continue;
224 for (Element
const that_element : that->elements_) {
225 if (this_element.object == that_element.object &&
226 this_element.index == that_element.index &&
227 this_element.value == that_element.value) {
228 copy->elements_[copy->next_index_++] = this_element;
233 copy->next_index_ %= arraysize(elements_);
237 void LoadElimination::AbstractElements::Print()
const {
238 for (Element
const& element : elements_) {
239 if (element.object) {
240 PrintF(
" #%d:%s @ #%d:%s -> #%d:%s\n", element.object->id(),
241 element.object->op()->mnemonic(), element.index->id(),
242 element.index->op()->mnemonic(), element.value->id(),
243 element.value->op()->mnemonic());
248 Node* LoadElimination::AbstractField::Lookup(Node*
object)
const {
249 for (
auto pair : info_for_node_) {
250 if (pair.first->IsDead())
continue;
251 if (MustAlias(
object, pair.first))
return pair.second.value;
258 bool MayAlias(MaybeHandle<Name> x, MaybeHandle<Name> y) {
259 if (!x.address())
return true;
260 if (!y.address())
return true;
261 if (x.address() != y.address())
return false;
270 : state_(state), object_(
object), map_(map) {}
272 : state_(state), object_(
object) {}
274 bool MayAlias(
Node* other)
const;
277 const AbstractState* state_;
282 LoadElimination::AbstractField
const* LoadElimination::AbstractField::Kill(
285 for (
auto pair : this->info_for_node_) {
286 if (pair.first->IsDead())
continue;
287 if (alias_info.MayAlias(pair.first)) {
288 AbstractField* that =
new (zone) AbstractField(zone);
289 for (
auto pair : this->info_for_node_) {
290 if (!alias_info.MayAlias(pair.first) ||
291 !MayAlias(name, pair.second.name)) {
292 that->info_for_node_.insert(pair);
301 void LoadElimination::AbstractField::Print()
const {
302 for (
auto pair : info_for_node_) {
303 PrintF(
" #%d:%s -> #%d:%s\n", pair.first->id(),
304 pair.first->op()->mnemonic(), pair.second.value->id(),
305 pair.second.value->op()->mnemonic());
309 LoadElimination::AbstractMaps::AbstractMaps(Zone* zone)
310 : info_for_node_(zone) {}
312 LoadElimination::AbstractMaps::AbstractMaps(Node*
object,
313 ZoneHandleSet<Map> maps, Zone* zone)
314 : info_for_node_(zone) {
315 object = ResolveRenames(
object);
316 info_for_node_.insert(std::make_pair(
object, maps));
319 bool LoadElimination::AbstractMaps::Lookup(
320 Node*
object, ZoneHandleSet<Map>* object_maps)
const {
321 auto it = info_for_node_.find(ResolveRenames(
object));
322 if (it == info_for_node_.end())
return false;
323 *object_maps = it->second;
327 LoadElimination::AbstractMaps
const* LoadElimination::AbstractMaps::Kill(
328 const AliasStateInfo& alias_info, Zone* zone)
const {
329 for (
auto pair : this->info_for_node_) {
330 if (alias_info.MayAlias(pair.first)) {
331 AbstractMaps* that =
new (zone) AbstractMaps(zone);
332 for (
auto pair : this->info_for_node_) {
333 if (!alias_info.MayAlias(pair.first)) that->info_for_node_.insert(pair);
341 LoadElimination::AbstractMaps
const* LoadElimination::AbstractMaps::Merge(
342 AbstractMaps
const* that, Zone* zone)
const {
343 if (this->Equals(that))
return this;
344 AbstractMaps* copy =
new (zone) AbstractMaps(zone);
345 for (
auto this_it : this->info_for_node_) {
346 Node* this_object = this_it.first;
347 ZoneHandleSet<Map> this_maps = this_it.second;
348 auto that_it = that->info_for_node_.find(this_object);
349 if (that_it != that->info_for_node_.end() && that_it->second == this_maps) {
350 copy->info_for_node_.insert(this_it);
356 LoadElimination::AbstractMaps
const* LoadElimination::AbstractMaps::Extend(
357 Node*
object, ZoneHandleSet<Map> maps, Zone* zone)
const {
358 AbstractMaps* that =
new (zone) AbstractMaps(zone);
359 that->info_for_node_ = this->info_for_node_;
360 object = ResolveRenames(
object);
361 that->info_for_node_[object] = maps;
365 void LoadElimination::AbstractMaps::Print()
const {
366 AllowHandleDereference allow_handle_dereference;
368 for (
auto pair : info_for_node_) {
369 os <<
" #" << pair.first->id() <<
":" << pair.first->op()->mnemonic()
371 ZoneHandleSet<Map>
const& maps = pair.second;
372 for (
size_t i = 0;
i < maps.size(); ++
i) {
373 os <<
" - " << Brief(*maps[
i]) << std::endl;
378 bool LoadElimination::AbstractState::Equals(AbstractState
const* that)
const {
379 if (this->elements_) {
380 if (!that->elements_ || !that->elements_->Equals(this->elements_)) {
383 }
else if (that->elements_) {
386 for (
size_t i = 0u;
i < arraysize(fields_); ++
i) {
387 AbstractField
const* this_field = this->fields_[
i];
388 AbstractField
const* that_field = that->fields_[
i];
390 if (!that_field || !that_field->Equals(this_field))
return false;
391 }
else if (that_field) {
396 if (!that->maps_ || !that->maps_->Equals(this->maps_)) {
399 }
else if (that->maps_) {
405 void LoadElimination::AbstractState::Merge(AbstractState
const* that,
408 if (this->elements_) {
409 this->elements_ = that->elements_
410 ? that->elements_->Merge(this->elements_, zone)
415 for (
size_t i = 0;
i < arraysize(fields_); ++
i) {
416 if (this->fields_[
i]) {
417 if (that->fields_[
i]) {
418 this->fields_[
i] = this->fields_[
i]->Merge(that->fields_[
i], zone);
420 this->fields_[
i] =
nullptr;
427 this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) :
nullptr;
431 bool LoadElimination::AbstractState::LookupMaps(
432 Node*
object, ZoneHandleSet<Map>* object_map)
const {
433 return this->maps_ && this->maps_->Lookup(
object, object_map);
436 LoadElimination::AbstractState
const* LoadElimination::AbstractState::SetMaps(
437 Node*
object, ZoneHandleSet<Map> maps, Zone* zone)
const {
438 AbstractState* that =
new (zone) AbstractState(*
this);
440 that->maps_ = that->maps_->Extend(
object, maps, zone);
442 that->maps_ =
new (zone) AbstractMaps(
object, maps, zone);
447 LoadElimination::AbstractState
const* LoadElimination::AbstractState::KillMaps(
448 const AliasStateInfo& alias_info, Zone* zone)
const {
450 AbstractMaps
const* that_maps = this->maps_->Kill(alias_info, zone);
451 if (this->maps_ != that_maps) {
452 AbstractState* that =
new (zone) AbstractState(*
this);
453 that->maps_ = that_maps;
460 LoadElimination::AbstractState
const* LoadElimination::AbstractState::KillMaps(
461 Node*
object, Zone* zone)
const {
462 AliasStateInfo alias_info(
this,
object);
463 return KillMaps(alias_info, zone);
466 Node* LoadElimination::AbstractState::LookupElement(
467 Node*
object, Node* index, MachineRepresentation representation)
const {
468 if (this->elements_) {
469 return this->elements_->Lookup(
object, index, representation);
474 LoadElimination::AbstractState
const*
475 LoadElimination::AbstractState::AddElement(Node*
object, Node* index,
477 MachineRepresentation representation,
479 AbstractState* that =
new (zone) AbstractState(*
this);
480 if (that->elements_) {
482 that->elements_->Extend(
object, index, value, representation, zone);
485 new (zone) AbstractElements(
object, index, value, representation, zone);
490 LoadElimination::AbstractState
const*
491 LoadElimination::AbstractState::KillElement(Node*
object, Node* index,
493 if (this->elements_) {
494 AbstractElements
const* that_elements =
495 this->elements_->Kill(
object, index, zone);
496 if (this->elements_ != that_elements) {
497 AbstractState* that =
new (zone) AbstractState(*
this);
498 that->elements_ = that_elements;
505 LoadElimination::AbstractState
const* LoadElimination::AbstractState::AddField(
506 Node*
object,
size_t index, Node* value, MaybeHandle<Name> name,
508 AbstractState* that =
new (zone) AbstractState(*
this);
509 if (that->fields_[index]) {
510 that->fields_[index] =
511 that->fields_[index]->Extend(
object, value, name, zone);
513 that->fields_[index] =
new (zone) AbstractField(
object, value, name, zone);
518 LoadElimination::AbstractState
const* LoadElimination::AbstractState::KillField(
519 Node*
object,
size_t index, MaybeHandle<Name> name, Zone* zone)
const {
520 AliasStateInfo alias_info(
this,
object);
521 return KillField(alias_info, index, name, zone);
524 LoadElimination::AbstractState
const* LoadElimination::AbstractState::KillField(
525 const AliasStateInfo& alias_info,
size_t index, MaybeHandle<Name> name,
527 if (AbstractField
const* this_field = this->fields_[index]) {
528 this_field = this_field->Kill(alias_info, name, zone);
529 if (this->fields_[index] != this_field) {
530 AbstractState* that =
new (zone) AbstractState(*
this);
531 that->fields_[index] = this_field;
538 LoadElimination::AbstractState
const*
539 LoadElimination::AbstractState::KillFields(Node*
object, MaybeHandle<Name> name,
541 AliasStateInfo alias_info(
this,
object);
542 for (
size_t i = 0;; ++
i) {
543 if (
i == arraysize(fields_))
return this;
544 if (AbstractField
const* this_field = this->fields_[
i]) {
545 AbstractField
const* that_field =
546 this_field->Kill(alias_info, name, zone);
547 if (that_field != this_field) {
548 AbstractState* that =
new (zone) AbstractState(*
this);
549 that->fields_[
i] = that_field;
550 while (++
i < arraysize(fields_)) {
551 if (this->fields_[
i] !=
nullptr) {
552 that->fields_[
i] = this->fields_[
i]->Kill(alias_info, name, zone);
561 Node* LoadElimination::AbstractState::LookupField(Node*
object,
562 size_t index)
const {
563 if (AbstractField
const* this_field = this->fields_[index]) {
564 return this_field->Lookup(
object);
569 bool LoadElimination::AliasStateInfo::MayAlias(Node* other)
const {
573 if (object_->opcode() == IrOpcode::kAllocate) {
574 return object_ == other;
577 if (!compiler::MayAlias(object_, other)) {
582 if (map_.ToHandle(&map)) {
583 ZoneHandleSet<Map> other_maps;
584 if (state_->LookupMaps(other, &other_maps) && other_maps.size() == 1) {
585 if (map.address() != other_maps.at(0).address()) {
593 void LoadElimination::AbstractState::Print()
const {
599 PrintF(
" elements:\n");
602 for (
size_t i = 0;
i < arraysize(fields_); ++
i) {
603 if (AbstractField
const*
const field = fields_[
i]) {
604 PrintF(
" field %zu:\n",
i);
610 LoadElimination::AbstractState
const*
611 LoadElimination::AbstractStateForEffectNodes::Get(Node* node)
const {
612 size_t const id = node->id();
613 if (
id < info_for_node_.size())
return info_for_node_[
id];
617 void LoadElimination::AbstractStateForEffectNodes::Set(
618 Node* node, AbstractState
const* state) {
619 size_t const id = node->id();
620 if (
id >= info_for_node_.size()) info_for_node_.resize(
id + 1,
nullptr);
621 info_for_node_[id] = state;
624 Reduction LoadElimination::ReduceMapGuard(Node* node) {
625 ZoneHandleSet<Map>
const maps = MapGuardMapsOf(node->op()).maps();
626 Node*
const object = NodeProperties::GetValueInput(node, 0);
627 Node*
const effect = NodeProperties::GetEffectInput(node);
628 AbstractState
const* state = node_states_.Get(effect);
629 if (state ==
nullptr)
return NoChange();
630 ZoneHandleSet<Map> object_maps;
631 if (state->LookupMaps(
object, &object_maps)) {
632 if (maps.contains(object_maps))
return Replace(effect);
635 state = state->SetMaps(
object, maps, zone());
636 return UpdateState(node, state);
639 Reduction LoadElimination::ReduceCheckMaps(Node* node) {
640 ZoneHandleSet<Map>
const maps = CheckMapsParametersOf(node->op()).maps();
641 Node*
const object = NodeProperties::GetValueInput(node, 0);
642 Node*
const effect = NodeProperties::GetEffectInput(node);
643 AbstractState
const* state = node_states_.Get(effect);
644 if (state ==
nullptr)
return NoChange();
645 ZoneHandleSet<Map> object_maps;
646 if (state->LookupMaps(
object, &object_maps)) {
647 if (maps.contains(object_maps))
return Replace(effect);
650 state = state->SetMaps(
object, maps, zone());
651 return UpdateState(node, state);
654 Reduction LoadElimination::ReduceCompareMaps(Node* node) {
655 ZoneHandleSet<Map>
const maps = CompareMapsParametersOf(node->op()).maps();
656 Node*
const object = NodeProperties::GetValueInput(node, 0);
657 Node*
const effect = NodeProperties::GetEffectInput(node);
658 AbstractState
const* state = node_states_.Get(effect);
659 if (state ==
nullptr)
return NoChange();
660 ZoneHandleSet<Map> object_maps;
661 if (state->LookupMaps(
object, &object_maps)) {
662 if (maps.contains(object_maps)) {
663 Node* value = jsgraph()->TrueConstant();
664 ReplaceWithValue(node, value, effect);
665 return Replace(value);
669 return UpdateState(node, state);
672 Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
673 Node*
const object = NodeProperties::GetValueInput(node, 0);
674 Node*
const elements = NodeProperties::GetValueInput(node, 1);
675 Node*
const effect = NodeProperties::GetEffectInput(node);
676 AbstractState
const* state = node_states_.Get(effect);
677 if (state ==
nullptr)
return NoChange();
679 ZoneHandleSet<Map> elements_maps;
680 ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
681 if (state->LookupMaps(elements, &elements_maps) &&
682 fixed_array_maps.contains(elements_maps)) {
683 ReplaceWithValue(node, elements, effect);
684 return Replace(elements);
687 state = state->SetMaps(node, fixed_array_maps, zone());
689 state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset),
690 MaybeHandle<Name>(), zone());
692 state = state->AddField(
object, FieldIndexOf(JSObject::kElementsOffset), node,
693 MaybeHandle<Name>(), zone());
694 return UpdateState(node, state);
697 Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
698 GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op());
699 Node*
const object = NodeProperties::GetValueInput(node, 0);
700 Node*
const effect = NodeProperties::GetEffectInput(node);
701 AbstractState
const* state = node_states_.Get(effect);
702 if (state ==
nullptr)
return NoChange();
703 if (params.mode() == GrowFastElementsMode::kDoubleElements) {
705 state = state->SetMaps(
706 node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone());
710 ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
711 fixed_array_maps.insert(factory()->fixed_cow_array_map(), zone());
712 state = state->SetMaps(node, fixed_array_maps, zone());
715 state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset),
716 MaybeHandle<Name>(), zone());
718 state = state->AddField(
object, FieldIndexOf(JSObject::kElementsOffset), node,
719 MaybeHandle<Name>(), zone());
720 return UpdateState(node, state);
723 Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
724 ElementsTransition transition = ElementsTransitionOf(node->op());
725 Node*
const object = NodeProperties::GetValueInput(node, 0);
726 Handle<Map> source_map(transition.source());
727 Handle<Map> target_map(transition.target());
728 Node*
const effect = NodeProperties::GetEffectInput(node);
729 AbstractState
const* state = node_states_.Get(effect);
730 if (state ==
nullptr)
return NoChange();
731 switch (transition.mode()) {
732 case ElementsTransition::kFastTransition:
734 case ElementsTransition::kSlowTransition:
736 AliasStateInfo alias_info(state,
object, source_map);
738 state->KillField(alias_info, FieldIndexOf(JSObject::kElementsOffset),
739 MaybeHandle<Name>(), zone());
742 ZoneHandleSet<Map> object_maps;
743 if (state->LookupMaps(
object, &object_maps)) {
744 if (ZoneHandleSet<Map>(target_map).contains(object_maps)) {
747 return Replace(effect);
749 if (object_maps.contains(ZoneHandleSet<Map>(source_map))) {
750 object_maps.remove(source_map, zone());
751 object_maps.insert(target_map, zone());
752 AliasStateInfo alias_info(state,
object, source_map);
753 state = state->KillMaps(alias_info, zone());
754 state = state->SetMaps(
object, object_maps, zone());
757 AliasStateInfo alias_info(state,
object, source_map);
758 state = state->KillMaps(alias_info, zone());
760 return UpdateState(node, state);
763 Reduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) {
764 Node*
const object = NodeProperties::GetValueInput(node, 0);
765 Handle<Map> double_map(DoubleMapParameterOf(node->op()));
766 Handle<Map> fast_map(FastMapParameterOf(node->op()));
767 Node*
const effect = NodeProperties::GetEffectInput(node);
768 AbstractState
const* state = node_states_.Get(effect);
769 if (state ==
nullptr)
return NoChange();
774 ZoneHandleSet<Map> object_maps;
775 if (state->LookupMaps(
object, &object_maps)) {
776 object_maps.insert(double_map, zone());
777 object_maps.insert(fast_map, zone());
778 state = state->KillMaps(
object, zone());
779 state = state->SetMaps(
object, object_maps, zone());
782 state = state->KillField(
object, FieldIndexOf(JSObject::kElementsOffset),
783 MaybeHandle<Name>(), zone());
784 return UpdateState(node, state);
787 Reduction LoadElimination::ReduceLoadField(Node* node) {
788 FieldAccess
const& access = FieldAccessOf(node->op());
789 Node*
object = NodeProperties::GetValueInput(node, 0);
790 Node* effect = NodeProperties::GetEffectInput(node);
791 Node* control = NodeProperties::GetControlInput(node);
792 AbstractState
const* state = node_states_.Get(effect);
793 if (state ==
nullptr)
return NoChange();
794 if (access.offset == HeapObject::kMapOffset &&
795 access.base_is_tagged == kTaggedBase) {
796 DCHECK(IsAnyTagged(access.machine_type.representation()));
797 ZoneHandleSet<Map> object_maps;
798 if (state->LookupMaps(
object, &object_maps) && object_maps.size() == 1) {
799 Node* value = jsgraph()->HeapConstant(object_maps[0]);
800 NodeProperties::SetType(value, Type::OtherInternal());
801 ReplaceWithValue(node, value, effect);
802 return Replace(value);
805 int field_index = FieldIndexOf(access);
806 if (field_index >= 0) {
807 if (Node* replacement = state->LookupField(
object, field_index)) {
809 if (!replacement->IsDead()) {
812 if (!NodeProperties::GetType(replacement)
813 .Is(NodeProperties::GetType(node))) {
814 Type replacement_type = Type::Intersect(
815 NodeProperties::GetType(node),
816 NodeProperties::GetType(replacement), graph()->zone());
817 replacement = effect =
818 graph()->NewNode(common()->TypeGuard(replacement_type),
819 replacement, effect, control);
820 NodeProperties::SetType(replacement, replacement_type);
822 ReplaceWithValue(node, replacement, effect);
823 return Replace(replacement);
826 state = state->AddField(
object, field_index, node, access.name, zone());
829 Handle<Map> field_map;
830 if (access.map.ToHandle(&field_map)) {
831 state = state->SetMaps(node, ZoneHandleSet<Map>(field_map), zone());
833 return UpdateState(node, state);
836 Reduction LoadElimination::ReduceStoreField(Node* node) {
837 FieldAccess
const& access = FieldAccessOf(node->op());
838 Node*
const object = NodeProperties::GetValueInput(node, 0);
839 Node*
const new_value = NodeProperties::GetValueInput(node, 1);
840 Node*
const effect = NodeProperties::GetEffectInput(node);
841 AbstractState
const* state = node_states_.Get(effect);
842 if (state ==
nullptr)
return NoChange();
843 if (access.offset == HeapObject::kMapOffset &&
844 access.base_is_tagged == kTaggedBase) {
845 DCHECK(IsAnyTagged(access.machine_type.representation()));
847 state = state->KillMaps(
object, zone());
848 Type const new_value_type = NodeProperties::GetType(new_value);
849 if (new_value_type.IsHeapConstant()) {
851 AllowHandleDereference handle_dereference;
852 ZoneHandleSet<Map> object_maps(
853 Handle<Map>::cast(new_value_type.AsHeapConstant()->Value()));
854 state = state->SetMaps(
object, object_maps, zone());
857 int field_index = FieldIndexOf(access);
858 if (field_index >= 0) {
859 Node*
const old_value = state->LookupField(
object, field_index);
860 if (old_value == new_value) {
862 return Replace(effect);
865 state = state->KillField(
object, field_index, access.name, zone());
867 state->AddField(
object, field_index, new_value, access.name, zone());
870 state = state->KillFields(
object, access.name, zone());
873 return UpdateState(node, state);
876 Reduction LoadElimination::ReduceLoadElement(Node* node) {
877 Node*
const object = NodeProperties::GetValueInput(node, 0);
878 Node*
const index = NodeProperties::GetValueInput(node, 1);
879 Node*
const effect = NodeProperties::GetEffectInput(node);
880 AbstractState
const* state = node_states_.Get(effect);
881 if (state ==
nullptr)
return NoChange();
884 ElementAccess
const& access = ElementAccessOf(node->op());
885 switch (access.machine_type.representation()) {
886 case MachineRepresentation::kNone:
887 case MachineRepresentation::kBit:
890 case MachineRepresentation::kWord8:
891 case MachineRepresentation::kWord16:
892 case MachineRepresentation::kWord32:
893 case MachineRepresentation::kWord64:
894 case MachineRepresentation::kFloat32:
897 case MachineRepresentation::kFloat64:
898 case MachineRepresentation::kSimd128:
899 case MachineRepresentation::kTaggedSigned:
900 case MachineRepresentation::kTaggedPointer:
901 case MachineRepresentation::kTagged:
902 if (Node* replacement = state->LookupElement(
903 object, index, access.machine_type.representation())) {
909 if (!replacement->IsDead() && NodeProperties::GetType(replacement)
910 .Is(NodeProperties::GetType(node))) {
911 ReplaceWithValue(node, replacement, effect);
912 return Replace(replacement);
915 state = state->AddElement(
object, index, node,
916 access.machine_type.representation(), zone());
917 return UpdateState(node, state);
922 Reduction LoadElimination::ReduceStoreElement(Node* node) {
923 ElementAccess
const& access = ElementAccessOf(node->op());
924 Node*
const object = NodeProperties::GetValueInput(node, 0);
925 Node*
const index = NodeProperties::GetValueInput(node, 1);
926 Node*
const new_value = NodeProperties::GetValueInput(node, 2);
927 Node*
const effect = NodeProperties::GetEffectInput(node);
928 AbstractState
const* state = node_states_.Get(effect);
929 if (state ==
nullptr)
return NoChange();
930 Node*
const old_value =
931 state->LookupElement(
object, index, access.machine_type.representation());
932 if (old_value == new_value) {
934 return Replace(effect);
937 state = state->KillElement(
object, index, zone());
939 switch (access.machine_type.representation()) {
940 case MachineRepresentation::kNone:
941 case MachineRepresentation::kBit:
944 case MachineRepresentation::kWord8:
945 case MachineRepresentation::kWord16:
946 case MachineRepresentation::kWord32:
947 case MachineRepresentation::kWord64:
948 case MachineRepresentation::kFloat32:
951 case MachineRepresentation::kFloat64:
952 case MachineRepresentation::kSimd128:
953 case MachineRepresentation::kTaggedSigned:
954 case MachineRepresentation::kTaggedPointer:
955 case MachineRepresentation::kTagged:
956 state = state->AddElement(
object, index, new_value,
957 access.machine_type.representation(), zone());
960 return UpdateState(node, state);
963 Reduction LoadElimination::ReduceStoreTypedElement(Node* node) {
964 Node*
const effect = NodeProperties::GetEffectInput(node);
965 AbstractState
const* state = node_states_.Get(effect);
966 if (state ==
nullptr)
return NoChange();
967 return UpdateState(node, state);
970 LoadElimination::AbstractState
const* LoadElimination::UpdateStateForPhi(
971 AbstractState
const* state, Node* effect_phi, Node* phi) {
972 int predecessor_count = phi->InputCount() - 1;
977 AbstractState
const* input_state =
978 node_states_.Get(NodeProperties::GetEffectInput(effect_phi, 0));
979 ZoneHandleSet<Map> object_maps;
980 if (!input_state->LookupMaps(phi->InputAt(0), &object_maps))
return state;
981 for (
int i = 1;
i < predecessor_count;
i++) {
983 node_states_.Get(NodeProperties::GetEffectInput(effect_phi,
i));
984 ZoneHandleSet<Map> input_maps;
985 if (!input_state->LookupMaps(phi->InputAt(
i), &input_maps))
return state;
986 if (input_maps != object_maps)
return state;
988 return state->SetMaps(phi, object_maps, zone());
991 Reduction LoadElimination::ReduceEffectPhi(Node* node) {
992 Node*
const effect0 = NodeProperties::GetEffectInput(node, 0);
993 Node*
const control = NodeProperties::GetControlInput(node);
994 AbstractState
const* state0 = node_states_.Get(effect0);
995 if (state0 ==
nullptr)
return NoChange();
996 if (control->opcode() == IrOpcode::kLoop) {
1000 AbstractState
const* state = ComputeLoopState(node, state0);
1001 return UpdateState(node, state);
1003 DCHECK_EQ(IrOpcode::kMerge, control->opcode());
1006 int const input_count = node->op()->EffectInputCount();
1007 for (
int i = 1;
i < input_count; ++
i) {
1008 Node*
const effect = NodeProperties::GetEffectInput(node,
i);
1009 if (node_states_.Get(effect) ==
nullptr)
return NoChange();
1014 AbstractState* state =
new (zone()) AbstractState(*state0);
1015 for (
int i = 1;
i < input_count; ++
i) {
1016 Node*
const input = NodeProperties::GetEffectInput(node,
i);
1017 state->Merge(node_states_.Get(input), zone());
1022 AbstractState
const* state_with_phis = state;
1023 for (Node* use : control->uses()) {
1024 if (use->opcode() == IrOpcode::kPhi) {
1025 state_with_phis = UpdateStateForPhi(state_with_phis, node, use);
1029 return UpdateState(node, state_with_phis);
1032 Reduction LoadElimination::ReduceStart(Node* node) {
1033 return UpdateState(node, empty_state());
1036 Reduction LoadElimination::ReduceOtherNode(Node* node) {
1037 if (node->op()->EffectInputCount() == 1) {
1038 if (node->op()->EffectOutputCount() == 1) {
1039 Node*
const effect = NodeProperties::GetEffectInput(node);
1040 AbstractState
const* state = node_states_.Get(effect);
1044 if (state ==
nullptr)
return NoChange();
1046 if (!node->op()->HasProperty(Operator::kNoWrite)) {
1047 state = empty_state();
1049 return UpdateState(node, state);
1055 DCHECK_EQ(0, node->op()->EffectInputCount());
1056 DCHECK_EQ(0, node->op()->EffectOutputCount());
1060 Reduction LoadElimination::UpdateState(Node* node, AbstractState
const* state) {
1061 AbstractState
const* original = node_states_.Get(node);
1064 if (state != original) {
1065 if (original ==
nullptr || !state->Equals(original)) {
1066 node_states_.Set(node, state);
1067 return Changed(node);
1073 LoadElimination::AbstractState
const* LoadElimination::ComputeLoopState(
1074 Node* node, AbstractState
const* state)
const {
1075 Node*
const control = NodeProperties::GetControlInput(node);
1076 struct TransitionElementsKindInfo {
1077 ElementsTransition transition;
1080 ZoneVector<TransitionElementsKindInfo> element_transitions_(zone());
1081 ZoneQueue<Node*> queue(zone());
1082 ZoneSet<Node*> visited(zone());
1083 visited.insert(node);
1084 for (
int i = 1;
i < control->InputCount(); ++
i) {
1085 queue.push(node->InputAt(
i));
1087 while (!queue.empty()) {
1088 Node*
const current = queue.front();
1090 if (visited.find(current) == visited.end()) {
1091 visited.insert(current);
1092 if (!current->op()->HasProperty(Operator::kNoWrite)) {
1093 switch (current->opcode()) {
1094 case IrOpcode::kEnsureWritableFastElements: {
1095 Node*
const object = NodeProperties::GetValueInput(current, 0);
1096 state = state->KillField(
object,
1097 FieldIndexOf(JSObject::kElementsOffset),
1098 MaybeHandle<Name>(), zone());
1101 case IrOpcode::kMaybeGrowFastElements: {
1102 Node*
const object = NodeProperties::GetValueInput(current, 0);
1103 state = state->KillField(
object,
1104 FieldIndexOf(JSObject::kElementsOffset),
1105 MaybeHandle<Name>(), zone());
1108 case IrOpcode::kTransitionElementsKind: {
1109 ElementsTransition transition = ElementsTransitionOf(current->op());
1110 Node*
const object = NodeProperties::GetValueInput(current, 0);
1111 ZoneHandleSet<Map> object_maps;
1112 if (!state->LookupMaps(
object, &object_maps) ||
1113 !ZoneHandleSet<Map>(transition.target())
1114 .contains(object_maps)) {
1115 element_transitions_.push_back({transition,
object});
1119 case IrOpcode::kTransitionAndStoreElement: {
1120 Node*
const object = NodeProperties::GetValueInput(current, 0);
1122 state = state->KillMaps(
object, zone());
1124 state = state->KillField(
object,
1125 FieldIndexOf(JSObject::kElementsOffset),
1126 MaybeHandle<Name>(), zone());
1129 case IrOpcode::kStoreField: {
1130 FieldAccess
const& access = FieldAccessOf(current->op());
1131 Node*
const object = NodeProperties::GetValueInput(current, 0);
1132 if (access.offset == HeapObject::kMapOffset) {
1134 state = state->KillMaps(
object, zone());
1136 int field_index = FieldIndexOf(access);
1137 if (field_index < 0) {
1138 state = state->KillFields(
object, access.name, zone());
1141 state->KillField(
object, field_index, access.name, zone());
1146 case IrOpcode::kStoreElement: {
1147 Node*
const object = NodeProperties::GetValueInput(current, 0);
1148 Node*
const index = NodeProperties::GetValueInput(current, 1);
1149 state = state->KillElement(
object, index, zone());
1152 case IrOpcode::kStoreTypedElement: {
1157 return empty_state();
1160 for (
int i = 0;
i < current->op()->EffectInputCount(); ++
i) {
1161 queue.push(NodeProperties::GetEffectInput(current,
i));
1190 for (
const TransitionElementsKindInfo& t : element_transitions_) {
1191 AliasStateInfo alias_info(state, t.object, t.transition.source());
1192 state = state->KillMaps(alias_info, zone());
1194 for (
const TransitionElementsKindInfo& t : element_transitions_) {
1195 switch (t.transition.mode()) {
1196 case ElementsTransition::kFastTransition:
1198 case ElementsTransition::kSlowTransition: {
1199 AliasStateInfo alias_info(state, t.object, t.transition.source());
1200 state = state->KillField(alias_info,
1201 FieldIndexOf(JSObject::kElementsOffset),
1202 MaybeHandle<Name>(), zone());
1211 int LoadElimination::FieldIndexOf(
int offset) {
1212 DCHECK_EQ(0, offset % kPointerSize);
1213 int field_index = offset / kPointerSize;
1214 if (field_index >= static_cast<int>(kMaxTrackedFields))
return -1;
1215 DCHECK_LT(0, field_index);
1216 return field_index - 1;
1220 int LoadElimination::FieldIndexOf(FieldAccess
const& access) {
1221 MachineRepresentation rep = access.machine_type.representation();
1223 case MachineRepresentation::kNone:
1224 case MachineRepresentation::kBit:
1225 case MachineRepresentation::kSimd128:
1228 case MachineRepresentation::kWord32:
1229 case MachineRepresentation::kWord64:
1230 if (rep != MachineType::PointerRepresentation()) {
1234 case MachineRepresentation::kWord8:
1235 case MachineRepresentation::kWord16:
1236 case MachineRepresentation::kFloat32:
1238 case MachineRepresentation::kFloat64:
1239 if (kDoubleSize != kPointerSize) {
1243 case MachineRepresentation::kTaggedSigned:
1244 case MachineRepresentation::kTaggedPointer:
1245 case MachineRepresentation::kTagged:
1250 if (access.base_is_tagged != kTaggedBase) {
1253 return FieldIndexOf(access.offset);
1256 CommonOperatorBuilder* LoadElimination::common()
const {
1257 return jsgraph()->common();
1260 Graph* LoadElimination::graph()
const {
return jsgraph()->graph(); }
1262 Isolate* LoadElimination::isolate()
const {
return jsgraph()->isolate(); }
1264 Factory* LoadElimination::factory()
const {
return jsgraph()->factory(); }