blob: 228375349da0b21105a9c23f74a352714890a0ce [file] [log] [blame]
Ben Murdochf91f0612016-11-29 16:50:11 +00001// Copyright 2016 the V8 project authors. All rights reserved.
Emily Bernier958fae72015-03-24 16:35:39 -04002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/load-elimination.h"
6
Rubin Xu7bc1b612021-02-16 09:38:50 +00007#include "src/compiler/access-builder.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +00008#include "src/compiler/common-operator.h"
Ben Murdochf91f0612016-11-29 16:50:11 +00009#include "src/compiler/js-graph.h"
Ben Murdoch014dc512016-03-22 12:00:34 +000010#include "src/compiler/node-properties.h"
Rubin Xu7bc1b612021-02-16 09:38:50 +000011#include "src/heap/factory.h"
12#include "src/objects/objects-inl.h"
Emily Bernier958fae72015-03-24 16:35:39 -040013
14namespace v8 {
15namespace internal {
16namespace compiler {
17
Ben Murdochf91f0612016-11-29 16:50:11 +000018namespace {
19
Rubin Xu7bc1b612021-02-16 09:38:50 +000020bool IsRename(Node* node) {
21 switch (node->opcode()) {
22 case IrOpcode::kCheckHeapObject:
23 case IrOpcode::kFinishRegion:
24 case IrOpcode::kTypeGuard:
25 return !node->IsDead();
26 default:
27 return false;
Ben Murdochf91f0612016-11-29 16:50:11 +000028 }
Rubin Xu7bc1b612021-02-16 09:38:50 +000029}
30
31Node* ResolveRenames(Node* node) {
32 while (IsRename(node)) {
33 node = node->InputAt(0);
34 }
35 return node;
36}
37
38bool MayAlias(Node* a, Node* b) {
39 if (a != b) {
40 if (!NodeProperties::GetType(a).Maybe(NodeProperties::GetType(b))) {
41 return false;
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) {
Ben Murdochf3b273f2017-01-17 12:11:28 +000047 switch (a->opcode()) {
48 case IrOpcode::kAllocate:
49 case IrOpcode::kHeapConstant:
50 case IrOpcode::kParameter:
Rubin Xu7bc1b612021-02-16 09:38:50 +000051 return false;
Ben Murdochf3b273f2017-01-17 12:11:28 +000052 default:
53 break;
54 }
Rubin Xu7bc1b612021-02-16 09:38:50 +000055 } else if (a->opcode() == IrOpcode::kAllocate) {
Ben Murdochf3b273f2017-01-17 12:11:28 +000056 switch (b->opcode()) {
57 case IrOpcode::kHeapConstant:
58 case IrOpcode::kParameter:
Rubin Xu7bc1b612021-02-16 09:38:50 +000059 return false;
Ben Murdochf3b273f2017-01-17 12:11:28 +000060 default:
61 break;
62 }
Ben Murdochf91f0612016-11-29 16:50:11 +000063 }
64 }
Rubin Xu7bc1b612021-02-16 09:38:50 +000065 return true;
Ben Murdochf91f0612016-11-29 16:50:11 +000066}
67
Rubin Xu7bc1b612021-02-16 09:38:50 +000068bool MustAlias(Node* a, Node* b) {
69 return ResolveRenames(a) == ResolveRenames(b);
70}
Ben Murdochf91f0612016-11-29 16:50:11 +000071
72} // namespace
Emily Bernier958fae72015-03-24 16:35:39 -040073
Emily Bernier958fae72015-03-24 16:35:39 -040074Reduction LoadElimination::Reduce(Node* node) {
Ben Murdochf3b273f2017-01-17 12:11:28 +000075 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) {
79 PrintF("(");
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());
84 }
85 PrintF(")");
86 }
87 PrintF("\n");
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());
93 state->Print();
94 } else {
95 PrintF(" no state[%i]: #%d:%s\n", i, effect->id(),
96 effect->op()->mnemonic());
97 }
98 }
99 }
100 }
Emily Bernier958fae72015-03-24 16:35:39 -0400101 switch (node->opcode()) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000102 case IrOpcode::kMapGuard:
103 return ReduceMapGuard(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000104 case IrOpcode::kCheckMaps:
105 return ReduceCheckMaps(node);
Rubin Xu7bc1b612021-02-16 09:38:50 +0000106 case IrOpcode::kCompareMaps:
107 return ReduceCompareMaps(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000108 case IrOpcode::kEnsureWritableFastElements:
109 return ReduceEnsureWritableFastElements(node);
110 case IrOpcode::kMaybeGrowFastElements:
111 return ReduceMaybeGrowFastElements(node);
112 case IrOpcode::kTransitionElementsKind:
113 return ReduceTransitionElementsKind(node);
Emily Bernier958fae72015-03-24 16:35:39 -0400114 case IrOpcode::kLoadField:
Rubin Xu7bc1b612021-02-16 09:38:50 +0000115 return ReduceLoadField(node, FieldAccessOf(node->op()));
Ben Murdochf91f0612016-11-29 16:50:11 +0000116 case IrOpcode::kStoreField:
Rubin Xu7bc1b612021-02-16 09:38:50 +0000117 return ReduceStoreField(node, FieldAccessOf(node->op()));
Ben Murdochf91f0612016-11-29 16:50:11 +0000118 case IrOpcode::kLoadElement:
119 return ReduceLoadElement(node);
120 case IrOpcode::kStoreElement:
121 return ReduceStoreElement(node);
Rubin Xu7bc1b612021-02-16 09:38:50 +0000122 case IrOpcode::kTransitionAndStoreElement:
123 return ReduceTransitionAndStoreElement(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000124 case IrOpcode::kStoreTypedElement:
125 return ReduceStoreTypedElement(node);
126 case IrOpcode::kEffectPhi:
127 return ReduceEffectPhi(node);
128 case IrOpcode::kDead:
Emily Bernier958fae72015-03-24 16:35:39 -0400129 break;
Ben Murdochf91f0612016-11-29 16:50:11 +0000130 case IrOpcode::kStart:
131 return ReduceStart(node);
132 default:
133 return ReduceOtherNode(node);
Emily Bernier958fae72015-03-24 16:35:39 -0400134 }
135 return NoChange();
136}
137
Ben Murdochf3b273f2017-01-17 12:11:28 +0000138namespace {
139
Rubin Xu7bc1b612021-02-16 09:38:50 +0000140bool IsCompatible(MachineRepresentation r1, MachineRepresentation r2) {
141 if (r1 == r2) return true;
142 return IsAnyTagged(r1) && IsAnyTagged(r2);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000143}
144
145} // namespace
146
Rubin Xu7bc1b612021-02-16 09:38:50 +0000147LoadElimination::AbstractState const
148 LoadElimination::AbstractState::empty_state_;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000149
Rubin Xu7bc1b612021-02-16 09:38:50 +0000150Node* LoadElimination::AbstractElements::Lookup(
151 Node* object, Node* index, MachineRepresentation representation) const {
Ben Murdochf91f0612016-11-29 16:50:11 +0000152 for (Element const element : elements_) {
153 if (element.object == nullptr) continue;
154 DCHECK_NOT_NULL(element.index);
155 DCHECK_NOT_NULL(element.value);
Rubin Xu7bc1b612021-02-16 09:38:50 +0000156 if (MustAlias(object, element.object) && MustAlias(index, element.index) &&
157 IsCompatible(representation, element.representation)) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000158 return element.value;
159 }
160 }
161 return nullptr;
162}
163
164LoadElimination::AbstractElements const*
165LoadElimination::AbstractElements::Kill(Node* object, Node* index,
166 Zone* zone) const {
167 for (Element const element : this->elements_) {
168 if (element.object == nullptr) continue;
169 if (MayAlias(object, element.object)) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000170 AbstractElements* that = zone->New<AbstractElements>(zone);
Ben Murdochf91f0612016-11-29 16:50:11 +0000171 for (Element const element : this->elements_) {
172 if (element.object == nullptr) continue;
173 DCHECK_NOT_NULL(element.index);
174 DCHECK_NOT_NULL(element.value);
175 if (!MayAlias(object, element.object) ||
Rubin Xu7bc1b612021-02-16 09:38:50 +0000176 !NodeProperties::GetType(index).Maybe(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000177 NodeProperties::GetType(element.index))) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000178 that->elements_[that->next_index_++] = element;
Emily Bernier958fae72015-03-24 16:35:39 -0400179 }
Emily Bernier958fae72015-03-24 16:35:39 -0400180 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000181 that->next_index_ %= arraysize(elements_);
182 return that;
183 }
184 }
185 return this;
186}
187
188bool LoadElimination::AbstractElements::Equals(
189 AbstractElements const* that) const {
190 if (this == that) return true;
191 for (size_t i = 0; i < arraysize(elements_); ++i) {
192 Element this_element = this->elements_[i];
193 if (this_element.object == nullptr) continue;
194 for (size_t j = 0;; ++j) {
195 if (j == arraysize(elements_)) return false;
196 Element that_element = that->elements_[j];
197 if (this_element.object == that_element.object &&
198 this_element.index == that_element.index &&
199 this_element.value == that_element.value) {
Emily Bernier958fae72015-03-24 16:35:39 -0400200 break;
201 }
202 }
203 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000204 for (size_t i = 0; i < arraysize(elements_); ++i) {
205 Element that_element = that->elements_[i];
206 if (that_element.object == nullptr) continue;
207 for (size_t j = 0;; ++j) {
208 if (j == arraysize(elements_)) return false;
209 Element this_element = this->elements_[j];
210 if (that_element.object == this_element.object &&
211 that_element.index == this_element.index &&
212 that_element.value == this_element.value) {
213 break;
214 }
215 }
216 }
217 return true;
218}
219
220LoadElimination::AbstractElements const*
221LoadElimination::AbstractElements::Merge(AbstractElements const* that,
222 Zone* zone) const {
223 if (this->Equals(that)) return this;
Rubin Xu7bc1b612021-02-16 09:38:50 +0000224 AbstractElements* copy = zone->New<AbstractElements>(zone);
Ben Murdochf91f0612016-11-29 16:50:11 +0000225 for (Element const this_element : this->elements_) {
226 if (this_element.object == nullptr) continue;
227 for (Element const that_element : that->elements_) {
228 if (this_element.object == that_element.object &&
229 this_element.index == that_element.index &&
230 this_element.value == that_element.value) {
231 copy->elements_[copy->next_index_++] = this_element;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000232 break;
Ben Murdochf91f0612016-11-29 16:50:11 +0000233 }
234 }
235 }
236 copy->next_index_ %= arraysize(elements_);
237 return copy;
238}
239
Ben Murdochf3b273f2017-01-17 12:11:28 +0000240void LoadElimination::AbstractElements::Print() const {
241 for (Element const& element : elements_) {
242 if (element.object) {
243 PrintF(" #%d:%s @ #%d:%s -> #%d:%s\n", element.object->id(),
244 element.object->op()->mnemonic(), element.index->id(),
245 element.index->op()->mnemonic(), element.value->id(),
246 element.value->op()->mnemonic());
247 }
248 }
249}
250
Rubin Xu7bc1b612021-02-16 09:38:50 +0000251LoadElimination::FieldInfo const* LoadElimination::AbstractField::Lookup(
252 Node* object) const {
253 for (auto& pair : info_for_node_) {
254 if (pair.first->IsDead()) continue;
255 if (MustAlias(object, pair.first)) return &pair.second;
Ben Murdochf91f0612016-11-29 16:50:11 +0000256 }
257 return nullptr;
258}
259
Rubin Xu7bc1b612021-02-16 09:38:50 +0000260namespace {
261
262bool MayAlias(MaybeHandle<Name> x, MaybeHandle<Name> y) {
263 if (!x.address()) return true;
264 if (!y.address()) return true;
265 if (x.address() != y.address()) return false;
266 return true;
267}
268
269} // namespace
270
271class LoadElimination::AliasStateInfo {
272 public:
273 AliasStateInfo(const AbstractState* state, Node* object, Handle<Map> map)
274 : state_(state), object_(object), map_(map) {}
275 AliasStateInfo(const AbstractState* state, Node* object)
276 : state_(state), object_(object) {}
277
278 bool MayAlias(Node* other) const;
279
280 private:
281 const AbstractState* state_;
282 Node* object_;
283 MaybeHandle<Map> map_;
284};
285
286LoadElimination::AbstractField const* LoadElimination::AbstractField::KillConst(
Ben Murdochf91f0612016-11-29 16:50:11 +0000287 Node* object, Zone* zone) const {
288 for (auto pair : this->info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000289 if (pair.first->IsDead()) continue;
290 // If we previously recorded information about a const store on the given
291 // 'object', we might not have done it on the same node; e.g. we might now
292 // identify the object by a FinishRegion node, whereas the initial const
293 // store was performed on the Allocate node. We therefore remove information
294 // on all nodes that must alias with 'object'.
295 if (MustAlias(object, pair.first)) {
296 AbstractField* that = zone->New<AbstractField>(zone);
Ben Murdochf91f0612016-11-29 16:50:11 +0000297 for (auto pair : this->info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000298 if (!MustAlias(object, pair.first)) {
299 that->info_for_node_.insert(pair);
300 }
301 }
302 return that;
303 }
304 }
305 return this;
306}
307
308LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
309 const AliasStateInfo& alias_info, MaybeHandle<Name> name,
310 Zone* zone) const {
311 for (auto pair : this->info_for_node_) {
312 if (pair.first->IsDead()) continue;
313 if (alias_info.MayAlias(pair.first)) {
314 AbstractField* that = zone->New<AbstractField>(zone);
315 for (auto pair : this->info_for_node_) {
316 if (!alias_info.MayAlias(pair.first) ||
317 !MayAlias(name, pair.second.name)) {
318 that->info_for_node_.insert(pair);
319 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000320 }
321 return that;
322 }
323 }
324 return this;
325}
326
Ben Murdochf3b273f2017-01-17 12:11:28 +0000327void LoadElimination::AbstractField::Print() const {
328 for (auto pair : info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000329 PrintF(" #%d:%s -> #%d:%s [repr=%s]\n", pair.first->id(),
330 pair.first->op()->mnemonic(), pair.second.value->id(),
331 pair.second.value->op()->mnemonic(),
332 MachineReprToString(pair.second.representation));
Ben Murdochf3b273f2017-01-17 12:11:28 +0000333 }
334}
335
Rubin Xu7bc1b612021-02-16 09:38:50 +0000336LoadElimination::AbstractMaps::AbstractMaps(Zone* zone)
337 : info_for_node_(zone) {}
338
339LoadElimination::AbstractMaps::AbstractMaps(Node* object,
340 ZoneHandleSet<Map> maps, Zone* zone)
341 : info_for_node_(zone) {
342 object = ResolveRenames(object);
343 info_for_node_.insert(std::make_pair(object, maps));
344}
345
Ben Murdoch62ed6312017-06-06 11:06:27 +0100346bool LoadElimination::AbstractMaps::Lookup(
347 Node* object, ZoneHandleSet<Map>* object_maps) const {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000348 auto it = info_for_node_.find(ResolveRenames(object));
349 if (it == info_for_node_.end()) return false;
350 *object_maps = it->second;
351 return true;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100352}
353
354LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Kill(
Rubin Xu7bc1b612021-02-16 09:38:50 +0000355 const AliasStateInfo& alias_info, Zone* zone) const {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100356 for (auto pair : this->info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000357 if (alias_info.MayAlias(pair.first)) {
358 AbstractMaps* that = zone->New<AbstractMaps>(zone);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100359 for (auto pair : this->info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000360 if (!alias_info.MayAlias(pair.first)) that->info_for_node_.insert(pair);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100361 }
362 return that;
363 }
364 }
365 return this;
366}
367
Rubin Xu7bc1b612021-02-16 09:38:50 +0000368LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Merge(
369 AbstractMaps const* that, Zone* zone) const {
370 if (this->Equals(that)) return this;
371 AbstractMaps* copy = zone->New<AbstractMaps>(zone);
372 for (auto this_it : this->info_for_node_) {
373 Node* this_object = this_it.first;
374 ZoneHandleSet<Map> this_maps = this_it.second;
375 auto that_it = that->info_for_node_.find(this_object);
376 if (that_it != that->info_for_node_.end() && that_it->second == this_maps) {
377 copy->info_for_node_.insert(this_it);
378 }
379 }
380 return copy;
381}
382
383LoadElimination::AbstractMaps const* LoadElimination::AbstractMaps::Extend(
384 Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
385 AbstractMaps* that = zone->New<AbstractMaps>(zone);
386 that->info_for_node_ = this->info_for_node_;
387 object = ResolveRenames(object);
388 that->info_for_node_[object] = maps;
389 return that;
390}
391
Ben Murdoch62ed6312017-06-06 11:06:27 +0100392void LoadElimination::AbstractMaps::Print() const {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000393 AllowHandleDereference allow_handle_dereference;
394 StdoutStream os;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100395 for (auto pair : info_for_node_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000396 os << " #" << pair.first->id() << ":" << pair.first->op()->mnemonic()
397 << std::endl;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100398 ZoneHandleSet<Map> const& maps = pair.second;
399 for (size_t i = 0; i < maps.size(); ++i) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000400 os << " - " << Brief(*maps[i]) << std::endl;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100401 }
402 }
403}
404
Rubin Xu7bc1b612021-02-16 09:38:50 +0000405bool LoadElimination::AbstractState::FieldsEquals(
406 AbstractFields const& this_fields,
407 AbstractFields const& that_fields) const {
408 for (size_t i = 0u; i < this_fields.size(); ++i) {
409 AbstractField const* this_field = this_fields[i];
410 AbstractField const* that_field = that_fields[i];
411 if (this_field) {
412 if (!that_field || !that_field->Equals(this_field)) return false;
413 } else if (that_field) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000414 return false;
415 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000416 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000417 return true;
418}
419
420bool LoadElimination::AbstractState::Equals(AbstractState const* that) const {
Ben Murdochf91f0612016-11-29 16:50:11 +0000421 if (this->elements_) {
422 if (!that->elements_ || !that->elements_->Equals(this->elements_)) {
423 return false;
424 }
425 } else if (that->elements_) {
426 return false;
427 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000428 if (!FieldsEquals(this->fields_, that->fields_) ||
429 !FieldsEquals(this->const_fields_, that->const_fields_)) {
430 return false;
Ben Murdochf91f0612016-11-29 16:50:11 +0000431 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100432 if (this->maps_) {
433 if (!that->maps_ || !that->maps_->Equals(this->maps_)) {
434 return false;
435 }
436 } else if (that->maps_) {
437 return false;
438 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000439 return true;
440}
441
Rubin Xu7bc1b612021-02-16 09:38:50 +0000442void LoadElimination::AbstractState::FieldsMerge(
443 AbstractFields* this_fields, AbstractFields const& that_fields,
444 Zone* zone) {
445 for (size_t i = 0; i < this_fields->size(); ++i) {
446 AbstractField const*& this_field = (*this_fields)[i];
447 if (this_field) {
448 if (that_fields[i]) {
449 this_field = this_field->Merge(that_fields[i], zone);
450 } else {
451 this_field = nullptr;
452 }
453 }
454 }
455}
456
Ben Murdochf91f0612016-11-29 16:50:11 +0000457void LoadElimination::AbstractState::Merge(AbstractState const* that,
458 Zone* zone) {
459 // Merge the information we have about the elements.
460 if (this->elements_) {
461 this->elements_ = that->elements_
462 ? that->elements_->Merge(this->elements_, zone)
Ben Murdochf3b273f2017-01-17 12:11:28 +0000463 : nullptr;
Ben Murdochf91f0612016-11-29 16:50:11 +0000464 }
465
466 // Merge the information we have about the fields.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000467 FieldsMerge(&this->fields_, that->fields_, zone);
468 FieldsMerge(&this->const_fields_, that->const_fields_, zone);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100469
470 // Merge the information we have about the maps.
471 if (this->maps_) {
472 this->maps_ = that->maps_ ? that->maps_->Merge(this->maps_, zone) : nullptr;
473 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000474}
475
Ben Murdoch62ed6312017-06-06 11:06:27 +0100476bool LoadElimination::AbstractState::LookupMaps(
477 Node* object, ZoneHandleSet<Map>* object_map) const {
478 return this->maps_ && this->maps_->Lookup(object, object_map);
479}
480
Rubin Xu7bc1b612021-02-16 09:38:50 +0000481LoadElimination::AbstractState const* LoadElimination::AbstractState::SetMaps(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100482 Node* object, ZoneHandleSet<Map> maps, Zone* zone) const {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000483 AbstractState* that = zone->New<AbstractState>(*this);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100484 if (that->maps_) {
485 that->maps_ = that->maps_->Extend(object, maps, zone);
486 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000487 that->maps_ = zone->New<AbstractMaps>(object, maps, zone);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100488 }
489 return that;
490}
491
492LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
Rubin Xu7bc1b612021-02-16 09:38:50 +0000493 const AliasStateInfo& alias_info, Zone* zone) const {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100494 if (this->maps_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000495 AbstractMaps const* that_maps = this->maps_->Kill(alias_info, zone);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100496 if (this->maps_ != that_maps) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000497 AbstractState* that = zone->New<AbstractState>(*this);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100498 that->maps_ = that_maps;
499 return that;
500 }
501 }
502 return this;
503}
504
Rubin Xu7bc1b612021-02-16 09:38:50 +0000505LoadElimination::AbstractState const* LoadElimination::AbstractState::KillMaps(
506 Node* object, Zone* zone) const {
507 AliasStateInfo alias_info(this, object);
508 return KillMaps(alias_info, zone);
509}
510
511Node* LoadElimination::AbstractState::LookupElement(
512 Node* object, Node* index, MachineRepresentation representation) const {
Ben Murdochf91f0612016-11-29 16:50:11 +0000513 if (this->elements_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000514 return this->elements_->Lookup(object, index, representation);
Ben Murdochf91f0612016-11-29 16:50:11 +0000515 }
516 return nullptr;
517}
518
519LoadElimination::AbstractState const*
520LoadElimination::AbstractState::AddElement(Node* object, Node* index,
Rubin Xu7bc1b612021-02-16 09:38:50 +0000521 Node* value,
522 MachineRepresentation representation,
523 Zone* zone) const {
524 AbstractState* that = zone->New<AbstractState>(*this);
Ben Murdochf91f0612016-11-29 16:50:11 +0000525 if (that->elements_) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000526 that->elements_ =
527 that->elements_->Extend(object, index, value, representation, zone);
Ben Murdochf91f0612016-11-29 16:50:11 +0000528 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000529 that->elements_ =
530 zone->New<AbstractElements>(object, index, value, representation, zone);
Ben Murdochf91f0612016-11-29 16:50:11 +0000531 }
532 return that;
533}
534
535LoadElimination::AbstractState const*
536LoadElimination::AbstractState::KillElement(Node* object, Node* index,
537 Zone* zone) const {
538 if (this->elements_) {
539 AbstractElements const* that_elements =
540 this->elements_->Kill(object, index, zone);
541 if (this->elements_ != that_elements) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000542 AbstractState* that = zone->New<AbstractState>(*this);
Ben Murdochf91f0612016-11-29 16:50:11 +0000543 that->elements_ = that_elements;
544 return that;
545 }
546 }
547 return this;
548}
549
550LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
Rubin Xu7bc1b612021-02-16 09:38:50 +0000551 Node* object, IndexRange index_range, LoadElimination::FieldInfo info,
552 Zone* zone) const {
553 AbstractState* that = zone->New<AbstractState>(*this);
554 AbstractFields& fields =
555 info.const_field_info.IsConst() ? that->const_fields_ : that->fields_;
556 for (int index : index_range) {
557 if (fields[index]) {
558 fields[index] = fields[index]->Extend(object, info, zone);
559 } else {
560 fields[index] = zone->New<AbstractField>(object, info, zone);
561 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000562 }
563 return that;
564}
565
Rubin Xu7bc1b612021-02-16 09:38:50 +0000566LoadElimination::AbstractState const*
567LoadElimination::AbstractState::KillConstField(Node* object,
568 IndexRange index_range,
569 Zone* zone) const {
570 AliasStateInfo alias_info(this, object);
571 AbstractState* that = nullptr;
572 for (int index : index_range) {
573 if (AbstractField const* this_field = this->const_fields_[index]) {
574 this_field = this_field->KillConst(object, zone);
575 if (this->const_fields_[index] != this_field) {
576 if (!that) that = zone->New<AbstractState>(*this);
577 that->const_fields_[index] = this_field;
578 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000579 }
580 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000581 return that ? that : this;
582}
583
584LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
585 Node* object, IndexRange index_range, MaybeHandle<Name> name,
586 Zone* zone) const {
587 AliasStateInfo alias_info(this, object);
588 return KillField(alias_info, index_range, name, zone);
589}
590
591LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
592 const AliasStateInfo& alias_info, IndexRange index_range,
593 MaybeHandle<Name> name, Zone* zone) const {
594 AbstractState* that = nullptr;
595 for (int index : index_range) {
596 if (AbstractField const* this_field = this->fields_[index]) {
597 this_field = this_field->Kill(alias_info, name, zone);
598 if (this->fields_[index] != this_field) {
599 if (!that) that = zone->New<AbstractState>(*this);
600 that->fields_[index] = this_field;
601 }
602 }
603 }
604 return that ? that : this;
Ben Murdochf91f0612016-11-29 16:50:11 +0000605}
606
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000607LoadElimination::AbstractState const*
Rubin Xu7bc1b612021-02-16 09:38:50 +0000608LoadElimination::AbstractState::KillFields(Node* object, MaybeHandle<Name> name,
609 Zone* zone) const {
610 AliasStateInfo alias_info(this, object);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000611 for (size_t i = 0;; ++i) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000612 if (i == fields_.size()) return this;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000613 if (AbstractField const* this_field = this->fields_[i]) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000614 AbstractField const* that_field =
615 this_field->Kill(alias_info, name, zone);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000616 if (that_field != this_field) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000617 AbstractState* that = zone->New<AbstractState>(*this);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100618 that->fields_[i] = that_field;
Rubin Xu7bc1b612021-02-16 09:38:50 +0000619 while (++i < fields_.size()) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000620 if (this->fields_[i] != nullptr) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000621 that->fields_[i] = this->fields_[i]->Kill(alias_info, name, zone);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000622 }
623 }
624 return that;
625 }
626 }
627 }
628}
629
Rubin Xu7bc1b612021-02-16 09:38:50 +0000630LoadElimination::AbstractState const* LoadElimination::AbstractState::KillAll(
631 Zone* zone) const {
632 // Kill everything except for const fields
633 for (size_t i = 0; i < const_fields_.size(); ++i) {
634 if (const_fields_[i]) {
635 AbstractState* that = zone->New<AbstractState>();
636 that->const_fields_ = const_fields_;
637 return that;
638 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000639 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000640 return LoadElimination::empty_state();
641}
642
643LoadElimination::FieldInfo const* LoadElimination::AbstractState::LookupField(
644 Node* object, IndexRange index_range,
645 ConstFieldInfo const_field_info) const {
646 // Check if all the indices in {index_range} contain identical information.
647 // If not, a partially overlapping access has invalidated part of the value.
648 base::Optional<LoadElimination::FieldInfo const*> result;
649 for (int index : index_range) {
650 LoadElimination::FieldInfo const* info = nullptr;
651 if (const_field_info.IsConst()) {
652 if (AbstractField const* this_field = const_fields_[index]) {
653 info = this_field->Lookup(object);
654 }
655 if (!(info && info->const_field_info == const_field_info)) return nullptr;
656 } else {
657 if (AbstractField const* this_field = fields_[index]) {
658 info = this_field->Lookup(object);
659 }
660 if (!info) return nullptr;
661 }
662 if (!result.has_value()) {
663 result = info;
664 } else if (**result != *info) {
665 // We detected inconsistent information for a field here.
666 // This can happen when incomplete alias information makes an unrelated
667 // write invalidate part of a field and then we re-combine this partial
668 // information.
669 // This is probably OK, but since it's rare, we better bail out here.
670 return nullptr;
671 }
672 }
673 return *result;
674}
675
676bool LoadElimination::AliasStateInfo::MayAlias(Node* other) const {
677 // If {object} is being initialized right here (indicated by {object} being
678 // an Allocate node instead of a FinishRegion node), we know that {other}
679 // can only alias with {object} if they refer to exactly the same node.
680 if (object_->opcode() == IrOpcode::kAllocate) {
681 return object_ == other;
682 }
683 // Decide aliasing based on the node kinds.
684 if (!compiler::MayAlias(object_, other)) {
685 return false;
686 }
687 // Decide aliasing based on maps (if available).
688 Handle<Map> map;
689 if (map_.ToHandle(&map)) {
690 ZoneHandleSet<Map> other_maps;
691 if (state_->LookupMaps(other, &other_maps) && other_maps.size() == 1) {
692 if (map.address() != other_maps.at(0).address()) {
693 return false;
694 }
695 }
696 }
697 return true;
Ben Murdochf91f0612016-11-29 16:50:11 +0000698}
699
Ben Murdochf3b273f2017-01-17 12:11:28 +0000700void LoadElimination::AbstractState::Print() const {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100701 if (maps_) {
702 PrintF(" maps:\n");
703 maps_->Print();
704 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000705 if (elements_) {
706 PrintF(" elements:\n");
707 elements_->Print();
708 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000709 for (size_t i = 0; i < fields_.size(); ++i) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000710 if (AbstractField const* const field = fields_[i]) {
711 PrintF(" field %zu:\n", i);
712 field->Print();
713 }
714 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000715 for (size_t i = 0; i < const_fields_.size(); ++i) {
716 if (AbstractField const* const const_field = const_fields_[i]) {
717 PrintF(" const field %zu:\n", i);
718 const_field->Print();
719 }
720 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000721}
722
Ben Murdochf91f0612016-11-29 16:50:11 +0000723LoadElimination::AbstractState const*
724LoadElimination::AbstractStateForEffectNodes::Get(Node* node) const {
725 size_t const id = node->id();
726 if (id < info_for_node_.size()) return info_for_node_[id];
727 return nullptr;
728}
729
730void LoadElimination::AbstractStateForEffectNodes::Set(
731 Node* node, AbstractState const* state) {
732 size_t const id = node->id();
733 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr);
734 info_for_node_[id] = state;
735}
736
Rubin Xu7bc1b612021-02-16 09:38:50 +0000737Reduction LoadElimination::ReduceMapGuard(Node* node) {
738 ZoneHandleSet<Map> const& maps = MapGuardMapsOf(node->op());
Ben Murdochf91f0612016-11-29 16:50:11 +0000739 Node* const object = NodeProperties::GetValueInput(node, 0);
740 Node* const effect = NodeProperties::GetEffectInput(node);
741 AbstractState const* state = node_states_.Get(effect);
742 if (state == nullptr) return NoChange();
Ben Murdoch62ed6312017-06-06 11:06:27 +0100743 ZoneHandleSet<Map> object_maps;
744 if (state->LookupMaps(object, &object_maps)) {
745 if (maps.contains(object_maps)) return Replace(effect);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100746 // TODO(turbofan): Compute the intersection.
Ben Murdochf91f0612016-11-29 16:50:11 +0000747 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000748 state = state->SetMaps(object, maps, zone());
749 return UpdateState(node, state);
750}
751
752Reduction LoadElimination::ReduceCheckMaps(Node* node) {
753 ZoneHandleSet<Map> const& maps = CheckMapsParametersOf(node->op()).maps();
754 Node* const object = NodeProperties::GetValueInput(node, 0);
755 Node* const effect = NodeProperties::GetEffectInput(node);
756 AbstractState const* state = node_states_.Get(effect);
757 if (state == nullptr) return NoChange();
758 ZoneHandleSet<Map> object_maps;
759 if (state->LookupMaps(object, &object_maps)) {
760 if (maps.contains(object_maps)) return Replace(effect);
761 // TODO(turbofan): Compute the intersection.
762 }
763 state = state->SetMaps(object, maps, zone());
764 return UpdateState(node, state);
765}
766
767Reduction LoadElimination::ReduceCompareMaps(Node* node) {
768 ZoneHandleSet<Map> const& maps = CompareMapsParametersOf(node->op());
769 Node* const object = NodeProperties::GetValueInput(node, 0);
770 Node* const effect = NodeProperties::GetEffectInput(node);
771 AbstractState const* state = node_states_.Get(effect);
772 if (state == nullptr) return NoChange();
773 ZoneHandleSet<Map> object_maps;
774 if (state->LookupMaps(object, &object_maps)) {
775 if (maps.contains(object_maps)) {
776 Node* value = jsgraph()->TrueConstant();
777 ReplaceWithValue(node, value, effect);
778 return Replace(value);
779 }
780 // TODO(turbofan): Compute the intersection.
781 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000782 return UpdateState(node, state);
783}
784
785Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
786 Node* const object = NodeProperties::GetValueInput(node, 0);
787 Node* const elements = NodeProperties::GetValueInput(node, 1);
788 Node* const effect = NodeProperties::GetEffectInput(node);
789 AbstractState const* state = node_states_.Get(effect);
790 if (state == nullptr) return NoChange();
Rubin Xu7bc1b612021-02-16 09:38:50 +0000791 // Check if the {elements} already have the fixed array map.
Ben Murdoch62ed6312017-06-06 11:06:27 +0100792 ZoneHandleSet<Map> elements_maps;
793 ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
794 if (state->LookupMaps(elements, &elements_maps) &&
795 fixed_array_maps.contains(elements_maps)) {
796 ReplaceWithValue(node, elements, effect);
797 return Replace(elements);
Ben Murdochf91f0612016-11-29 16:50:11 +0000798 }
799 // We know that the resulting elements have the fixed array map.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000800 state = state->SetMaps(node, fixed_array_maps, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000801 // Kill the previous elements on {object}.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000802 state = state->KillField(object,
803 FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
804 MaybeHandle<Name>(), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000805 // Add the new elements on {object}.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000806 state = state->AddField(
807 object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
808 {node, MachineRepresentation::kTaggedPointer}, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000809 return UpdateState(node, state);
810}
811
812Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000813 GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op());
Ben Murdochf91f0612016-11-29 16:50:11 +0000814 Node* const object = NodeProperties::GetValueInput(node, 0);
815 Node* const effect = NodeProperties::GetEffectInput(node);
816 AbstractState const* state = node_states_.Get(effect);
817 if (state == nullptr) return NoChange();
Rubin Xu7bc1b612021-02-16 09:38:50 +0000818 if (params.mode() == GrowFastElementsMode::kDoubleElements) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000819 // We know that the resulting elements have the fixed double array map.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000820 state = state->SetMaps(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100821 node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000822 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000823 // We know that the resulting elements have the fixed array map or the COW
824 // version thereof (if we didn't grow and it was already COW before).
825 ZoneHandleSet<Map> fixed_array_maps(factory()->fixed_array_map());
826 fixed_array_maps.insert(factory()->fixed_cow_array_map(), zone());
827 state = state->SetMaps(node, fixed_array_maps, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000828 }
829 // Kill the previous elements on {object}.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000830 state = state->KillField(object,
831 FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
832 MaybeHandle<Name>(), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000833 // Add the new elements on {object}.
Rubin Xu7bc1b612021-02-16 09:38:50 +0000834 state = state->AddField(
835 object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
836 {node, MachineRepresentation::kTaggedPointer}, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000837 return UpdateState(node, state);
838}
839
840Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100841 ElementsTransition transition = ElementsTransitionOf(node->op());
Ben Murdochf91f0612016-11-29 16:50:11 +0000842 Node* const object = NodeProperties::GetValueInput(node, 0);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100843 Handle<Map> source_map(transition.source());
844 Handle<Map> target_map(transition.target());
Ben Murdochf91f0612016-11-29 16:50:11 +0000845 Node* const effect = NodeProperties::GetEffectInput(node);
846 AbstractState const* state = node_states_.Get(effect);
847 if (state == nullptr) return NoChange();
Rubin Xu7bc1b612021-02-16 09:38:50 +0000848 switch (transition.mode()) {
849 case ElementsTransition::kFastTransition:
850 break;
851 case ElementsTransition::kSlowTransition:
852 // Kill the elements as well.
853 AliasStateInfo alias_info(state, object, source_map);
854 state = state->KillField(
855 alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
856 MaybeHandle<Name>(), zone());
857 break;
858 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100859 ZoneHandleSet<Map> object_maps;
860 if (state->LookupMaps(object, &object_maps)) {
861 if (ZoneHandleSet<Map>(target_map).contains(object_maps)) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000862 // The {object} already has the {target_map}, so this TransitionElements
863 // {node} is fully redundant (independent of what {source_map} is).
864 return Replace(effect);
865 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100866 if (object_maps.contains(ZoneHandleSet<Map>(source_map))) {
867 object_maps.remove(source_map, zone());
868 object_maps.insert(target_map, zone());
Rubin Xu7bc1b612021-02-16 09:38:50 +0000869 AliasStateInfo alias_info(state, object, source_map);
870 state = state->KillMaps(alias_info, zone());
871 state = state->SetMaps(object, object_maps, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000872 }
873 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000874 AliasStateInfo alias_info(state, object, source_map);
875 state = state->KillMaps(alias_info, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000876 }
877 return UpdateState(node, state);
878}
879
Rubin Xu7bc1b612021-02-16 09:38:50 +0000880Reduction LoadElimination::ReduceTransitionAndStoreElement(Node* node) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000881 Node* const object = NodeProperties::GetValueInput(node, 0);
Rubin Xu7bc1b612021-02-16 09:38:50 +0000882 Handle<Map> double_map(DoubleMapParameterOf(node->op()));
883 Handle<Map> fast_map(FastMapParameterOf(node->op()));
Ben Murdochf91f0612016-11-29 16:50:11 +0000884 Node* const effect = NodeProperties::GetEffectInput(node);
Rubin Xu7bc1b612021-02-16 09:38:50 +0000885 AbstractState const* state = node_states_.Get(effect);
886 if (state == nullptr) return NoChange();
887
888 // We need to add the double and fast maps to the set of possible maps for
889 // this object, because we don't know which of those we'll transition to.
890 // Additionally, we should kill all alias information.
891 ZoneHandleSet<Map> object_maps;
892 if (state->LookupMaps(object, &object_maps)) {
893 object_maps.insert(double_map, zone());
894 object_maps.insert(fast_map, zone());
895 state = state->KillMaps(object, zone());
896 state = state->SetMaps(object, object_maps, zone());
897 }
898 // Kill the elements as well.
899 state = state->KillField(object,
900 FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
901 MaybeHandle<Name>(), zone());
902 return UpdateState(node, state);
903}
904
905Reduction LoadElimination::ReduceLoadField(Node* node,
906 FieldAccess const& access) {
907 Node* object = NodeProperties::GetValueInput(node, 0);
908 Node* effect = NodeProperties::GetEffectInput(node);
909 Node* control = NodeProperties::GetControlInput(node);
Ben Murdochf91f0612016-11-29 16:50:11 +0000910 AbstractState const* state = node_states_.Get(effect);
911 if (state == nullptr) return NoChange();
Ben Murdoch62ed6312017-06-06 11:06:27 +0100912 if (access.offset == HeapObject::kMapOffset &&
913 access.base_is_tagged == kTaggedBase) {
914 DCHECK(IsAnyTagged(access.machine_type.representation()));
915 ZoneHandleSet<Map> object_maps;
916 if (state->LookupMaps(object, &object_maps) && object_maps.size() == 1) {
917 Node* value = jsgraph()->HeapConstant(object_maps[0]);
918 NodeProperties::SetType(value, Type::OtherInternal());
919 ReplaceWithValue(node, value, effect);
920 return Replace(value);
Ben Murdochf91f0612016-11-29 16:50:11 +0000921 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100922 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000923 IndexRange field_index = FieldIndexOf(access);
924 if (field_index != IndexRange::Invalid()) {
925 MachineRepresentation representation =
926 access.machine_type.representation();
927 FieldInfo const* lookup_result =
928 state->LookupField(object, field_index, access.const_field_info);
929 if (!lookup_result && access.const_field_info.IsConst()) {
930 // If the access is const and we didn't find anything, also try to look
931 // up information from mutable stores
932 lookup_result =
933 state->LookupField(object, field_index, ConstFieldInfo::None());
934 }
935 if (lookup_result) {
936 // Make sure we don't reuse values that were recorded with a different
937 // representation or resurrect dead {replacement} nodes.
938 Node* replacement = lookup_result->value;
939 if (IsCompatible(representation, lookup_result->representation) &&
940 !replacement->IsDead()) {
941 // Introduce a TypeGuard if the type of the {replacement} node is not
942 // a subtype of the original {node}'s type.
943 if (!NodeProperties::GetType(replacement)
944 .Is(NodeProperties::GetType(node))) {
945 Type replacement_type = Type::Intersect(
946 NodeProperties::GetType(node),
947 NodeProperties::GetType(replacement), graph()->zone());
948 replacement = effect =
949 graph()->NewNode(common()->TypeGuard(replacement_type),
950 replacement, effect, control);
951 NodeProperties::SetType(replacement, replacement_type);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100952 }
953 ReplaceWithValue(node, replacement, effect);
954 return Replace(replacement);
955 }
956 }
Rubin Xu7bc1b612021-02-16 09:38:50 +0000957 FieldInfo info(node, representation, access.name,
958 access.const_field_info);
959 state = state->AddField(object, field_index, info, zone());
Ben Murdoch62ed6312017-06-06 11:06:27 +0100960 }
961 }
962 Handle<Map> field_map;
963 if (access.map.ToHandle(&field_map)) {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000964 state = state->SetMaps(node, ZoneHandleSet<Map>(field_map), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000965 }
966 return UpdateState(node, state);
967}
968
Rubin Xu7bc1b612021-02-16 09:38:50 +0000969Reduction LoadElimination::ReduceStoreField(Node* node,
970 FieldAccess const& access) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000971 Node* const object = NodeProperties::GetValueInput(node, 0);
972 Node* const new_value = NodeProperties::GetValueInput(node, 1);
973 Node* const effect = NodeProperties::GetEffectInput(node);
974 AbstractState const* state = node_states_.Get(effect);
975 if (state == nullptr) return NoChange();
Ben Murdoch62ed6312017-06-06 11:06:27 +0100976 if (access.offset == HeapObject::kMapOffset &&
977 access.base_is_tagged == kTaggedBase) {
978 DCHECK(IsAnyTagged(access.machine_type.representation()));
979 // Kill all potential knowledge about the {object}s map.
980 state = state->KillMaps(object, zone());
Rubin Xu7bc1b612021-02-16 09:38:50 +0000981 Type const new_value_type = NodeProperties::GetType(new_value);
982 if (new_value_type.IsHeapConstant()) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100983 // Record the new {object} map information.
984 ZoneHandleSet<Map> object_maps(
Rubin Xu7bc1b612021-02-16 09:38:50 +0000985 new_value_type.AsHeapConstant()->Ref().AsMap().object());
986 state = state->SetMaps(object, object_maps, zone());
Ben Murdochf91f0612016-11-29 16:50:11 +0000987 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000988 } else {
Rubin Xu7bc1b612021-02-16 09:38:50 +0000989 IndexRange field_index = FieldIndexOf(access);
990 if (field_index != IndexRange::Invalid()) {
991 bool is_const_store = access.const_field_info.IsConst();
992 MachineRepresentation representation =
993 access.machine_type.representation();
994 FieldInfo const* lookup_result =
995 state->LookupField(object, field_index, access.const_field_info);
996
997 if (lookup_result &&
998 (!is_const_store || V8_ENABLE_DOUBLE_CONST_STORE_CHECK_BOOL)) {
999 // At runtime, we should never encounter
1000 // - any store replacing existing info with a different, incompatible
1001 // representation, nor
1002 // - two consecutive const stores, unless the latter is a store into
1003 // a literal.
1004 // However, we may see such code statically, so we guard against
1005 // executing it by emitting Unreachable.
1006 // TODO(gsps): Re-enable the double const store check even for
1007 // non-debug builds once we have identified other FieldAccesses
1008 // that should be marked mutable instead of const
1009 // (cf. JSCreateLowering::AllocateFastLiteral).
1010 bool incompatible_representation =
1011 !lookup_result->name.is_null() &&
1012 !IsCompatible(representation, lookup_result->representation);
1013 bool illegal_double_const_store =
1014 is_const_store && !access.is_store_in_literal;
1015 if (incompatible_representation || illegal_double_const_store) {
1016 Node* control = NodeProperties::GetControlInput(node);
1017 Node* unreachable =
1018 graph()->NewNode(common()->Unreachable(), effect, control);
1019 return Replace(unreachable);
1020 }
1021 if (lookup_result->value == new_value) {
1022 // This store is fully redundant.
1023 return Replace(effect);
1024 }
Ben Murdoch62ed6312017-06-06 11:06:27 +01001025 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001026
Ben Murdoch62ed6312017-06-06 11:06:27 +01001027 // Kill all potentially aliasing fields and record the new value.
Rubin Xu7bc1b612021-02-16 09:38:50 +00001028 FieldInfo new_info(new_value, representation, access.name,
1029 access.const_field_info);
1030 if (is_const_store && access.is_store_in_literal) {
1031 // We only kill const information when there is a chance that we
1032 // previously stored information about the given const field (namely,
1033 // when we observe const stores to literals).
1034 state = state->KillConstField(object, field_index, zone());
1035 }
1036 state = state->KillField(object, field_index, access.name, zone());
1037 state = state->AddField(object, field_index, new_info, zone());
1038 if (is_const_store) {
1039 // For const stores, we track information in both the const and the
1040 // mutable world to guard against field accesses that should have
1041 // been marked const, but were not.
1042 new_info.const_field_info = ConstFieldInfo::None();
1043 state = state->AddField(object, field_index, new_info, zone());
1044 }
Ben Murdoch62ed6312017-06-06 11:06:27 +01001045 } else {
1046 // Unsupported StoreField operator.
Rubin Xu7bc1b612021-02-16 09:38:50 +00001047 state = state->KillFields(object, access.name, zone());
Ben Murdoch62ed6312017-06-06 11:06:27 +01001048 }
Ben Murdochf91f0612016-11-29 16:50:11 +00001049 }
1050 return UpdateState(node, state);
1051}
1052
1053Reduction LoadElimination::ReduceLoadElement(Node* node) {
1054 Node* const object = NodeProperties::GetValueInput(node, 0);
1055 Node* const index = NodeProperties::GetValueInput(node, 1);
1056 Node* const effect = NodeProperties::GetEffectInput(node);
1057 AbstractState const* state = node_states_.Get(effect);
1058 if (state == nullptr) return NoChange();
Rubin Xu7bc1b612021-02-16 09:38:50 +00001059
1060 // Only handle loads that do not require truncations.
1061 ElementAccess const& access = ElementAccessOf(node->op());
1062 switch (access.machine_type.representation()) {
1063 case MachineRepresentation::kNone:
1064 case MachineRepresentation::kBit:
1065 case MachineRepresentation::kWord8:
1066 case MachineRepresentation::kWord16:
1067 case MachineRepresentation::kWord32:
1068 case MachineRepresentation::kWord64:
1069 case MachineRepresentation::kFloat32:
1070 case MachineRepresentation::kCompressedPointer:
1071 case MachineRepresentation::kCompressed:
1072 // TODO(turbofan): Add support for doing the truncations.
1073 break;
1074 case MachineRepresentation::kFloat64:
1075 case MachineRepresentation::kSimd128:
1076 case MachineRepresentation::kTaggedSigned:
1077 case MachineRepresentation::kTaggedPointer:
1078 case MachineRepresentation::kTagged:
1079 if (Node* replacement = state->LookupElement(
1080 object, index, access.machine_type.representation())) {
1081 // Make sure we don't resurrect dead {replacement} nodes.
1082 // Skip lowering if the type of the {replacement} node is not a subtype
1083 // of the original {node}'s type.
1084 // TODO(tebbi): We should insert a {TypeGuard} for the intersection of
1085 // these two types here once we properly handle {Type::None} everywhere.
1086 if (!replacement->IsDead() && NodeProperties::GetType(replacement)
1087 .Is(NodeProperties::GetType(node))) {
1088 ReplaceWithValue(node, replacement, effect);
1089 return Replace(replacement);
1090 }
Ben Murdochf3b273f2017-01-17 12:11:28 +00001091 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001092 state = state->AddElement(object, index, node,
1093 access.machine_type.representation(), zone());
1094 return UpdateState(node, state);
Ben Murdochf91f0612016-11-29 16:50:11 +00001095 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001096 return NoChange();
Ben Murdochf91f0612016-11-29 16:50:11 +00001097}
1098
1099Reduction LoadElimination::ReduceStoreElement(Node* node) {
1100 ElementAccess const& access = ElementAccessOf(node->op());
1101 Node* const object = NodeProperties::GetValueInput(node, 0);
1102 Node* const index = NodeProperties::GetValueInput(node, 1);
1103 Node* const new_value = NodeProperties::GetValueInput(node, 2);
1104 Node* const effect = NodeProperties::GetEffectInput(node);
1105 AbstractState const* state = node_states_.Get(effect);
1106 if (state == nullptr) return NoChange();
Rubin Xu7bc1b612021-02-16 09:38:50 +00001107 Node* const old_value =
1108 state->LookupElement(object, index, access.machine_type.representation());
Ben Murdochf91f0612016-11-29 16:50:11 +00001109 if (old_value == new_value) {
1110 // This store is fully redundant.
1111 return Replace(effect);
1112 }
1113 // Kill all potentially aliasing elements.
1114 state = state->KillElement(object, index, zone());
1115 // Only record the new value if the store doesn't have an implicit truncation.
1116 switch (access.machine_type.representation()) {
1117 case MachineRepresentation::kNone:
1118 case MachineRepresentation::kBit:
Ben Murdochf91f0612016-11-29 16:50:11 +00001119 case MachineRepresentation::kWord8:
1120 case MachineRepresentation::kWord16:
1121 case MachineRepresentation::kWord32:
1122 case MachineRepresentation::kWord64:
1123 case MachineRepresentation::kFloat32:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001124 case MachineRepresentation::kCompressedPointer:
1125 case MachineRepresentation::kCompressed:
Ben Murdochf91f0612016-11-29 16:50:11 +00001126 // TODO(turbofan): Add support for doing the truncations.
1127 break;
1128 case MachineRepresentation::kFloat64:
1129 case MachineRepresentation::kSimd128:
1130 case MachineRepresentation::kTaggedSigned:
1131 case MachineRepresentation::kTaggedPointer:
1132 case MachineRepresentation::kTagged:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001133 state = state->AddElement(object, index, new_value,
1134 access.machine_type.representation(), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +00001135 break;
1136 }
1137 return UpdateState(node, state);
1138}
1139
1140Reduction LoadElimination::ReduceStoreTypedElement(Node* node) {
1141 Node* const effect = NodeProperties::GetEffectInput(node);
1142 AbstractState const* state = node_states_.Get(effect);
1143 if (state == nullptr) return NoChange();
1144 return UpdateState(node, state);
1145}
1146
Rubin Xu7bc1b612021-02-16 09:38:50 +00001147LoadElimination::AbstractState const* LoadElimination::UpdateStateForPhi(
1148 AbstractState const* state, Node* effect_phi, Node* phi) {
1149 int predecessor_count = phi->InputCount() - 1;
1150 // TODO(jarin) Consider doing a union here. At the moment, we just keep this
1151 // consistent with AbstractState::Merge.
1152
1153 // Check if all the inputs have the same maps.
1154 AbstractState const* input_state =
1155 node_states_.Get(NodeProperties::GetEffectInput(effect_phi, 0));
1156 ZoneHandleSet<Map> object_maps;
1157 if (!input_state->LookupMaps(phi->InputAt(0), &object_maps)) return state;
1158 for (int i = 1; i < predecessor_count; i++) {
1159 input_state =
1160 node_states_.Get(NodeProperties::GetEffectInput(effect_phi, i));
1161 ZoneHandleSet<Map> input_maps;
1162 if (!input_state->LookupMaps(phi->InputAt(i), &input_maps)) return state;
1163 if (input_maps != object_maps) return state;
1164 }
1165 return state->SetMaps(phi, object_maps, zone());
1166}
1167
Ben Murdochf91f0612016-11-29 16:50:11 +00001168Reduction LoadElimination::ReduceEffectPhi(Node* node) {
1169 Node* const effect0 = NodeProperties::GetEffectInput(node, 0);
1170 Node* const control = NodeProperties::GetControlInput(node);
1171 AbstractState const* state0 = node_states_.Get(effect0);
1172 if (state0 == nullptr) return NoChange();
1173 if (control->opcode() == IrOpcode::kLoop) {
1174 // Here we rely on having only reducible loops:
1175 // The loop entry edge always dominates the header, so we can just take
1176 // the state from the first input, and compute the loop state based on it.
1177 AbstractState const* state = ComputeLoopState(node, state0);
1178 return UpdateState(node, state);
1179 }
1180 DCHECK_EQ(IrOpcode::kMerge, control->opcode());
1181
1182 // Shortcut for the case when we do not know anything about some input.
1183 int const input_count = node->op()->EffectInputCount();
1184 for (int i = 1; i < input_count; ++i) {
1185 Node* const effect = NodeProperties::GetEffectInput(node, i);
1186 if (node_states_.Get(effect) == nullptr) return NoChange();
1187 }
1188
1189 // Make a copy of the first input's state and merge with the state
1190 // from other inputs.
Rubin Xu7bc1b612021-02-16 09:38:50 +00001191 AbstractState* state = zone()->New<AbstractState>(*state0);
Ben Murdochf91f0612016-11-29 16:50:11 +00001192 for (int i = 1; i < input_count; ++i) {
1193 Node* const input = NodeProperties::GetEffectInput(node, i);
1194 state->Merge(node_states_.Get(input), zone());
1195 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001196
1197 // For each phi, try to compute the new state for the phi from
1198 // the inputs.
1199 AbstractState const* state_with_phis = state;
1200 for (Node* use : control->uses()) {
1201 if (use->opcode() == IrOpcode::kPhi) {
1202 state_with_phis = UpdateStateForPhi(state_with_phis, node, use);
1203 }
1204 }
1205
1206 return UpdateState(node, state_with_phis);
Ben Murdochf91f0612016-11-29 16:50:11 +00001207}
1208
1209Reduction LoadElimination::ReduceStart(Node* node) {
1210 return UpdateState(node, empty_state());
1211}
1212
1213Reduction LoadElimination::ReduceOtherNode(Node* node) {
1214 if (node->op()->EffectInputCount() == 1) {
1215 if (node->op()->EffectOutputCount() == 1) {
1216 Node* const effect = NodeProperties::GetEffectInput(node);
1217 AbstractState const* state = node_states_.Get(effect);
1218 // If we do not know anything about the predecessor, do not propagate
1219 // just yet because we will have to recompute anyway once we compute
1220 // the predecessor.
1221 if (state == nullptr) return NoChange();
1222 // Check if this {node} has some uncontrolled side effects.
1223 if (!node->op()->HasProperty(Operator::kNoWrite)) {
Rubin Xu7bc1b612021-02-16 09:38:50 +00001224 state = state->KillAll(zone());
Ben Murdochf91f0612016-11-29 16:50:11 +00001225 }
1226 return UpdateState(node, state);
1227 } else {
1228 // Effect terminators should be handled specially.
1229 return NoChange();
1230 }
1231 }
1232 DCHECK_EQ(0, node->op()->EffectInputCount());
1233 DCHECK_EQ(0, node->op()->EffectOutputCount());
Emily Bernier958fae72015-03-24 16:35:39 -04001234 return NoChange();
1235}
1236
Ben Murdochf91f0612016-11-29 16:50:11 +00001237Reduction LoadElimination::UpdateState(Node* node, AbstractState const* state) {
1238 AbstractState const* original = node_states_.Get(node);
1239 // Only signal that the {node} has Changed, if the information about {state}
1240 // has changed wrt. the {original}.
1241 if (state != original) {
1242 if (original == nullptr || !state->Equals(original)) {
1243 node_states_.Set(node, state);
1244 return Changed(node);
1245 }
1246 }
1247 return NoChange();
1248}
1249
Rubin Xu7bc1b612021-02-16 09:38:50 +00001250LoadElimination::AbstractState const*
1251LoadElimination::ComputeLoopStateForStoreField(
1252 Node* current, LoadElimination::AbstractState const* state,
1253 FieldAccess const& access) const {
1254 Node* const object = NodeProperties::GetValueInput(current, 0);
1255 if (access.offset == HeapObject::kMapOffset) {
1256 // Invalidate what we know about the {object}s map.
1257 state = state->KillMaps(object, zone());
1258 } else {
1259 IndexRange field_index = FieldIndexOf(access);
1260 if (field_index == IndexRange::Invalid()) {
1261 state = state->KillFields(object, access.name, zone());
1262 } else {
1263 state = state->KillField(object, field_index, access.name, zone());
1264 }
1265 }
1266 return state;
1267}
1268
Ben Murdochf91f0612016-11-29 16:50:11 +00001269LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
1270 Node* node, AbstractState const* state) const {
1271 Node* const control = NodeProperties::GetControlInput(node);
Rubin Xu7bc1b612021-02-16 09:38:50 +00001272 struct TransitionElementsKindInfo {
1273 ElementsTransition transition;
1274 Node* object;
1275 };
1276 // Allocate zone data structures in a temporary zone with a lifetime limited
1277 // to this function to avoid blowing up the size of the stage-global zone.
1278 Zone temp_zone(zone()->allocator(), "Temporary scoped zone");
1279 ZoneVector<TransitionElementsKindInfo> element_transitions_(&temp_zone);
1280 ZoneQueue<Node*> queue(&temp_zone);
1281 ZoneSet<Node*> visited(&temp_zone);
Ben Murdochf91f0612016-11-29 16:50:11 +00001282 visited.insert(node);
1283 for (int i = 1; i < control->InputCount(); ++i) {
1284 queue.push(node->InputAt(i));
1285 }
1286 while (!queue.empty()) {
1287 Node* const current = queue.front();
1288 queue.pop();
1289 if (visited.find(current) == visited.end()) {
1290 visited.insert(current);
1291 if (!current->op()->HasProperty(Operator::kNoWrite)) {
1292 switch (current->opcode()) {
1293 case IrOpcode::kEnsureWritableFastElements: {
1294 Node* const object = NodeProperties::GetValueInput(current, 0);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001295 state = state->KillField(
Rubin Xu7bc1b612021-02-16 09:38:50 +00001296 object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
1297 MaybeHandle<Name>(), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +00001298 break;
1299 }
1300 case IrOpcode::kMaybeGrowFastElements: {
Ben Murdochf91f0612016-11-29 16:50:11 +00001301 Node* const object = NodeProperties::GetValueInput(current, 0);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001302 state = state->KillField(
Rubin Xu7bc1b612021-02-16 09:38:50 +00001303 object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
1304 MaybeHandle<Name>(), zone());
Ben Murdochf91f0612016-11-29 16:50:11 +00001305 break;
1306 }
1307 case IrOpcode::kTransitionElementsKind: {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001308 ElementsTransition transition = ElementsTransitionOf(current->op());
Ben Murdochf91f0612016-11-29 16:50:11 +00001309 Node* const object = NodeProperties::GetValueInput(current, 0);
Ben Murdoch62ed6312017-06-06 11:06:27 +01001310 ZoneHandleSet<Map> object_maps;
1311 if (!state->LookupMaps(object, &object_maps) ||
1312 !ZoneHandleSet<Map>(transition.target())
1313 .contains(object_maps)) {
Rubin Xu7bc1b612021-02-16 09:38:50 +00001314 element_transitions_.push_back({transition, object});
Ben Murdoch62ed6312017-06-06 11:06:27 +01001315 }
Ben Murdochf91f0612016-11-29 16:50:11 +00001316 break;
1317 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001318 case IrOpcode::kTransitionAndStoreElement: {
Ben Murdochf91f0612016-11-29 16:50:11 +00001319 Node* const object = NodeProperties::GetValueInput(current, 0);
Rubin Xu7bc1b612021-02-16 09:38:50 +00001320 // Invalidate what we know about the {object}s map.
1321 state = state->KillMaps(object, zone());
1322 // Kill the elements as well.
1323 state = state->KillField(
1324 object, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
1325 MaybeHandle<Name>(), zone());
1326 break;
1327 }
1328 case IrOpcode::kStoreField: {
1329 FieldAccess access = FieldAccessOf(current->op());
1330 state = ComputeLoopStateForStoreField(current, state, access);
Ben Murdochf91f0612016-11-29 16:50:11 +00001331 break;
1332 }
1333 case IrOpcode::kStoreElement: {
1334 Node* const object = NodeProperties::GetValueInput(current, 0);
1335 Node* const index = NodeProperties::GetValueInput(current, 1);
1336 state = state->KillElement(object, index, zone());
1337 break;
1338 }
Ben Murdochf91f0612016-11-29 16:50:11 +00001339 case IrOpcode::kStoreTypedElement: {
1340 // Doesn't affect anything we track with the state currently.
1341 break;
1342 }
1343 default:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001344 return state->KillAll(zone());
Ben Murdochf91f0612016-11-29 16:50:11 +00001345 }
1346 }
1347 for (int i = 0; i < current->op()->EffectInputCount(); ++i) {
1348 queue.push(NodeProperties::GetEffectInput(current, i));
1349 }
1350 }
1351 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001352
1353 // Finally, we apply the element transitions. For each transition, we will try
1354 // to only invalidate information about nodes that can have the transition's
1355 // source map. The trouble is that an object can be transitioned by some other
1356 // transition to the source map. In that case, the other transition will
1357 // invalidate the information, so we are mostly fine.
1358 //
1359 // The only bad case is
1360 //
1361 // mapA ---fast---> mapB ---slow---> mapC
1362 //
1363 // If we process the slow transition first on an object that has mapA, we will
1364 // ignore the transition because the object does not have its source map
1365 // (mapB). When we later process the fast transition, we invalidate the
1366 // object's map, but we keep the information about the object's elements. This
1367 // is wrong because the elements will be overwritten by the slow transition.
1368 //
1369 // Note that the slow-slow case is fine because either of the slow transition
1370 // will invalidate the elements field, so the processing order does not
1371 // matter.
1372 //
1373 // To handle the bad case properly, we first kill the maps using all
1374 // transitions. We kill the the fields later when all the transitions are
1375 // already reflected in the map information.
1376
1377 for (const TransitionElementsKindInfo& t : element_transitions_) {
1378 AliasStateInfo alias_info(state, t.object, t.transition.source());
1379 state = state->KillMaps(alias_info, zone());
1380 }
1381 for (const TransitionElementsKindInfo& t : element_transitions_) {
1382 switch (t.transition.mode()) {
1383 case ElementsTransition::kFastTransition:
1384 break;
1385 case ElementsTransition::kSlowTransition: {
1386 AliasStateInfo alias_info(state, t.object, t.transition.source());
1387 state = state->KillField(
1388 alias_info, FieldIndexOf(JSObject::kElementsOffset, kTaggedSize),
1389 MaybeHandle<Name>(), zone());
1390 break;
1391 }
1392 }
1393 }
Ben Murdochf91f0612016-11-29 16:50:11 +00001394 return state;
1395}
1396
1397// static
Rubin Xu7bc1b612021-02-16 09:38:50 +00001398LoadElimination::IndexRange LoadElimination::FieldIndexOf(
1399 int offset, int representation_size) {
1400 DCHECK(IsAligned(offset, kTaggedSize));
1401 int field_index = offset / kTaggedSize - 1;
1402 DCHECK_EQ(0, representation_size % kTaggedSize);
1403 return IndexRange(field_index, representation_size / kTaggedSize);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001404}
1405
1406// static
Rubin Xu7bc1b612021-02-16 09:38:50 +00001407LoadElimination::IndexRange LoadElimination::FieldIndexOf(
1408 FieldAccess const& access) {
Ben Murdochf91f0612016-11-29 16:50:11 +00001409 MachineRepresentation rep = access.machine_type.representation();
1410 switch (rep) {
1411 case MachineRepresentation::kNone:
1412 case MachineRepresentation::kBit:
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001413 case MachineRepresentation::kSimd128:
Ben Murdochf91f0612016-11-29 16:50:11 +00001414 UNREACHABLE();
Ben Murdochf91f0612016-11-29 16:50:11 +00001415 case MachineRepresentation::kWord8:
1416 case MachineRepresentation::kWord16:
1417 case MachineRepresentation::kFloat32:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001418 // Currently untracked.
1419 return IndexRange::Invalid();
Ben Murdochf91f0612016-11-29 16:50:11 +00001420 case MachineRepresentation::kFloat64:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001421 case MachineRepresentation::kWord32:
1422 case MachineRepresentation::kWord64:
Ben Murdochf91f0612016-11-29 16:50:11 +00001423 case MachineRepresentation::kTaggedSigned:
1424 case MachineRepresentation::kTaggedPointer:
1425 case MachineRepresentation::kTagged:
Rubin Xu7bc1b612021-02-16 09:38:50 +00001426 case MachineRepresentation::kCompressedPointer:
1427 case MachineRepresentation::kCompressed:
Ben Murdochf91f0612016-11-29 16:50:11 +00001428 break;
1429 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001430 int representation_size = ElementSizeInBytes(rep);
1431 // We currently only track fields that are at least tagged pointer sized.
1432 if (representation_size < kTaggedSize) return IndexRange::Invalid();
1433 DCHECK_EQ(0, representation_size % kTaggedSize);
1434
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001435 if (access.base_is_tagged != kTaggedBase) {
Rubin Xu7bc1b612021-02-16 09:38:50 +00001436 // We currently only track tagged objects.
1437 return IndexRange::Invalid();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001438 }
Rubin Xu7bc1b612021-02-16 09:38:50 +00001439 return FieldIndexOf(access.offset, representation_size);
Ben Murdochf91f0612016-11-29 16:50:11 +00001440}
1441
Ben Murdochf3b273f2017-01-17 12:11:28 +00001442CommonOperatorBuilder* LoadElimination::common() const {
1443 return jsgraph()->common();
1444}
1445
1446Graph* LoadElimination::graph() const { return jsgraph()->graph(); }
1447
Rubin Xu7bc1b612021-02-16 09:38:50 +00001448Isolate* LoadElimination::isolate() const { return jsgraph()->isolate(); }
1449
Ben Murdoch62ed6312017-06-06 11:06:27 +01001450Factory* LoadElimination::factory() const { return jsgraph()->factory(); }
1451
Emily Bernier958fae72015-03-24 16:35:39 -04001452} // namespace compiler
1453} // namespace internal
1454} // namespace v8