v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
load-elimination.h
Go to the documentation of this file.
1// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_COMPILER_LOAD_ELIMINATION_H_
6#define V8_COMPILER_LOAD_ELIMINATION_H_
7
10#include "src/common/globals.h"
14
15namespace v8 {
16namespace internal {
17
18// Forward declarations.
19class Factory;
20
21namespace compiler {
22
23// Forward declarations.
24class CommonOperatorBuilder;
25struct FieldAccess;
26class TFGraph;
27class JSGraph;
28
30 : public NON_EXPORTED_BASE(AdvancedReducer) {
31 public:
33 Zone* zone)
34 : AdvancedReducer(editor),
36 node_states_(zone),
37 jsgraph_(jsgraph) {}
38 ~LoadElimination() final = default;
40 LoadElimination& operator=(const LoadElimination&) = delete;
41
42 const char* reducer_name() const override { return "LoadElimination"; }
43
44 Reduction Reduce(Node* node) final;
45
46 private:
47 static const size_t kMaxTrackedElements = 8;
48
49 // Abstract state to approximate the current state of an element along the
50 // effect paths through the graph.
51 class AbstractElements final : public ZoneObject {
52 public:
53 explicit AbstractElements(Zone* zone) {
54 for (size_t i = 0; i < arraysize(elements_); ++i) {
55 elements_[i] = Element();
56 }
57 }
58 AbstractElements(Node* object, Node* index, Node* value,
59 MachineRepresentation representation, Zone* zone)
60 : AbstractElements(zone) {
61 elements_[next_index_++] = Element(object, index, value, representation);
62 }
63
64 AbstractElements const* Extend(Node* object, Node* index, Node* value,
65 MachineRepresentation representation,
66 Zone* zone) const {
67 AbstractElements* that = zone->New<AbstractElements>(*this);
68 that->elements_[that->next_index_] =
69 Element(object, index, value, representation);
70 that->next_index_ = (that->next_index_ + 1) % arraysize(elements_);
71 return that;
72 }
73 Node* Lookup(Node* object, Node* index,
74 MachineRepresentation representation) const;
75 AbstractElements const* Kill(Node* object, Node* index, Zone* zone) const;
76 bool Equals(AbstractElements const* that) const;
77 AbstractElements const* Merge(AbstractElements const* that,
78 Zone* zone) const;
79
80 void Print() const;
81
82 private:
83 struct Element {
84 Element() = default;
85 Element(Node* object, Node* index, Node* value,
86 MachineRepresentation representation)
87 : object(object),
88 index(index),
89 value(value),
90 representation(representation) {}
91
92 Node* object = nullptr;
93 Node* index = nullptr;
94 Node* value = nullptr;
95 MachineRepresentation representation = MachineRepresentation::kNone;
96 };
97
98 Element elements_[kMaxTrackedElements];
99 size_t next_index_ = 0;
100 };
101
102 // Information we use to resolve object aliasing. Currently, we consider
103 // object not aliased if they have different maps or if the nodes may
104 // not alias.
105 class AliasStateInfo;
106
107 struct FieldInfo {
108 FieldInfo() = default;
109 FieldInfo(Node* value, MachineRepresentation representation,
110 MaybeHandle<Name> name = {},
111 ConstFieldInfo const_field_info = ConstFieldInfo::None())
112 : value(value),
113 representation(representation),
114 name(name),
115 const_field_info(const_field_info) {}
116
117 bool operator==(const FieldInfo& other) const {
118 return value == other.value && representation == other.representation &&
119 name.address() == other.name.address() &&
120 const_field_info == other.const_field_info;
121 }
122 bool operator!=(const FieldInfo& other) const { return !(*this == other); }
123
124 Node* value = nullptr;
125 MachineRepresentation representation = MachineRepresentation::kNone;
128 };
129
130 // Abstract state to approximate the current state of a certain field along
131 // the effect paths through the graph.
132 class AbstractField final : public ZoneObject {
133 public:
134 explicit AbstractField(Zone* zone) : info_for_node_(zone) {}
135 AbstractField(Node* object, FieldInfo info, Zone* zone)
136 : info_for_node_(zone) {
137 info_for_node_.insert(std::make_pair(object, info));
138 }
139
140 AbstractField const* Extend(Node* object, FieldInfo info, Zone* zone,
141 int current_field_count) const {
142 AbstractField* that = zone->New<AbstractField>(*this);
143 if ((current_field_count >= kMaxTrackedFields &&
144 that->info_for_node_.size() > 0) ||
145 that->info_for_node_.size() >= kMaxTrackedObjects) {
146 // We are tracking too many objects, which leads to bad performance.
147 // Delete one to avoid the map from becoming bigger.
148 that->info_for_node_.erase(that->info_for_node_.begin());
149 }
150 that->info_for_node_[object] = info;
151 return that;
152 }
153 FieldInfo const* Lookup(Node* object) const;
154 AbstractField const* KillConst(Node* object, Zone* zone) const;
155 AbstractField const* Kill(const AliasStateInfo& alias_info,
156 MaybeHandle<Name> name, Zone* zone) const;
157 bool Equals(AbstractField const* that) const {
158 return this == that || this->info_for_node_ == that->info_for_node_;
159 }
160 AbstractField const* Merge(AbstractField const* that, Zone* zone,
161 int* count) const {
162 if (this->Equals(that)) return this;
163 AbstractField* copy = zone->New<AbstractField>(zone);
164 for (auto this_it : this->info_for_node_) {
165 Node* this_object = this_it.first;
166 FieldInfo this_second = this_it.second;
167 if (this_object->IsDead()) continue;
168 auto that_it = that->info_for_node_.find(this_object);
169 if (that_it != that->info_for_node_.end() &&
170 that_it->second == this_second) {
171 copy->info_for_node_.insert(this_it);
172 (*count)++;
173 }
174 }
175 return copy;
176 }
177
178 void Print() const;
179
180 int count() const { return static_cast<int>(info_for_node_.size()); }
181
182 private:
184 };
185
186 static size_t const kMaxTrackedFieldsPerObject = 32;
187 static size_t const kMaxTrackedObjects = 100;
188 static int const kMaxTrackedFields = 300;
189
190 // Abstract state to approximate the current map of an object along the
191 // effect paths through the graph.
192 class AbstractMaps final : public ZoneObject {
193 public:
194 explicit AbstractMaps(Zone* zone);
195 AbstractMaps(Node* object, ZoneRefSet<Map> maps, Zone* zone);
196
197 AbstractMaps const* Extend(Node* object, ZoneRefSet<Map> maps,
198 Zone* zone) const;
199 bool Lookup(Node* object, ZoneRefSet<Map>* object_maps) const;
200 AbstractMaps const* Kill(const AliasStateInfo& alias_info,
201 Zone* zone) const;
202 bool Equals(AbstractMaps const* that) const {
203 return this == that || this->info_for_node_ == that->info_for_node_;
204 }
205 AbstractMaps const* Merge(AbstractMaps const* that, Zone* zone) const;
206
207 void Print() const;
208
209 private:
211 };
212
214 public:
215 IndexRange(int begin, int size) : begin_(begin), end_(begin + size) {
216 DCHECK_LE(0, begin);
217 DCHECK_LE(1, size);
218 if (end_ > static_cast<int>(kMaxTrackedFieldsPerObject)) {
219 *this = IndexRange::Invalid();
220 }
221 }
222 static IndexRange Invalid() { return IndexRange(); }
223
224 bool operator==(const IndexRange& other) const {
225 return begin_ == other.begin_ && end_ == other.end_;
226 }
227 bool operator!=(const IndexRange& other) const { return !(*this == other); }
228
229 struct Iterator {
230 int i;
231 int operator*() { return i; }
232 void operator++() { ++i; }
233 bool operator!=(Iterator other) { return i != other.i; }
234 };
235
236 Iterator begin() { return {begin_}; }
237 Iterator end() { return {end_}; }
238
239 private:
241 int end_;
242
243 IndexRange() : begin_(-1), end_(-1) {}
244 };
245
246 class AbstractState final : public ZoneObject {
247 public:
248 bool Equals(AbstractState const* that) const;
249 void Merge(AbstractState const* that, Zone* zone);
250
251 AbstractState const* SetMaps(Node* object, ZoneRefSet<Map> maps,
252 Zone* zone) const;
253 AbstractState const* KillMaps(Node* object, Zone* zone) const;
254 AbstractState const* KillMaps(const AliasStateInfo& alias_info,
255 Zone* zone) const;
256 bool LookupMaps(Node* object, ZoneRefSet<Map>* object_maps) const;
257
258 AbstractState const* AddField(Node* object, IndexRange index,
259 FieldInfo info, Zone* zone) const;
260 AbstractState const* KillConstField(Node* object, IndexRange index_range,
261 Zone* zone) const;
262 AbstractState const* KillField(const AliasStateInfo& alias_info,
263 IndexRange index, MaybeHandle<Name> name,
264 Zone* zone) const;
265 AbstractState const* KillField(Node* object, IndexRange index,
266 MaybeHandle<Name> name, Zone* zone) const;
267 AbstractState const* KillFields(Node* object, MaybeHandle<Name> name,
268 Zone* zone) const;
269 AbstractState const* KillAll(Zone* zone) const;
270 FieldInfo const* LookupField(Node* object, IndexRange index,
271 ConstFieldInfo const_field_info) const;
272
273 AbstractState const* AddElement(Node* object, Node* index, Node* value,
274 MachineRepresentation representation,
275 Zone* zone) const;
276 AbstractState const* KillElement(Node* object, Node* index,
277 Zone* zone) const;
278 Node* LookupElement(Node* object, Node* index,
279 MachineRepresentation representation) const;
280
281 void Print() const;
282
283 static AbstractState const* empty_state() { return &empty_state_; }
284
285 private:
287
289 std::array<AbstractField const*, kMaxTrackedFieldsPerObject>;
290
291 bool FieldsEquals(AbstractFields const& this_fields,
292 AbstractFields const& that_fields) const;
293 void FieldsMerge(AbstractFields* this_fields,
294 AbstractFields const& that_fields, Zone* zone);
295
296 AbstractElements const* elements_ = nullptr;
297 AbstractFields fields_{};
298 AbstractFields const_fields_{};
299 AbstractMaps const* maps_ = nullptr;
300 int const_fields_count_ = 0;
301 // Note that fields_count_ includes both const_fields and non-const fields.
302 // To get the number of non-const fields, use `fields_count_ -
303 // const_fields_count_`.
304 int fields_count_ = 0;
305 };
306
308 public:
309 explicit AbstractStateForEffectNodes(Zone* zone) : info_for_node_(zone) {}
310 AbstractState const* Get(Node* node) const;
311 void Set(Node* node, AbstractState const* state);
312
313 Zone* zone() const { return info_for_node_.zone(); }
314
315 private:
317 };
318
319 Reduction ReduceCheckMaps(Node* node);
320 Reduction ReduceCompareMaps(Node* node);
321 Reduction ReduceMapGuard(Node* node);
322 Reduction ReduceEnsureWritableFastElements(Node* node);
323 Reduction ReduceMaybeGrowFastElements(Node* node);
324 Reduction ReduceTransitionElementsKind(Node* node);
325 Reduction ReduceTransitionElementsKindOrCheckMap(Node* node);
326 Reduction ReduceLoadField(Node* node, FieldAccess const& access);
327 Reduction ReduceStoreField(Node* node, FieldAccess const& access);
328 Reduction ReduceLoadElement(Node* node);
329 Reduction ReduceStoreElement(Node* node);
330 Reduction ReduceTransitionAndStoreElement(Node* node);
331 Reduction ReduceStoreTypedElement(Node* node);
332 Reduction ReduceEffectPhi(Node* node);
333 Reduction ReduceStart(Node* node);
334 Reduction ReduceOtherNode(Node* node);
335
336 Reduction UpdateState(Node* node, AbstractState const* state);
337
338 AbstractState const* ComputeLoopState(Node* node,
339 AbstractState const* state) const;
340 AbstractState const* ComputeLoopStateForStoreField(
341 Node* current, LoadElimination::AbstractState const* state,
342 FieldAccess const& access) const;
343 AbstractState const* UpdateStateForPhi(AbstractState const* state,
344 Node* effect_phi, Node* phi);
345
346 static IndexRange FieldIndexOf(int offset, int representation_size);
347 static IndexRange FieldIndexOf(FieldAccess const& access);
348
349 static AbstractState const* empty_state() {
350 return AbstractState::empty_state();
351 }
352
353 CommonOperatorBuilder* common() const;
354 Isolate* isolate() const;
355 Factory* factory() const;
356 TFGraph* graph() const;
357 JSGraph* jsgraph() const { return jsgraph_; }
358 JSHeapBroker* broker() const { return broker_; }
359 Zone* zone() const { return node_states_.zone(); }
360
364};
365
366} // namespace compiler
367} // namespace internal
368} // namespace v8
369
370#endif // V8_COMPILER_LOAD_ELIMINATION_H_
TFGraph * graph
JSGraph * jsgraph
T * New(Args &&... args)
Definition zone.h:114
AbstractElements(Node *object, Node *index, Node *value, MachineRepresentation representation, Zone *zone)
AbstractElements const * Extend(Node *object, Node *index, Node *value, MachineRepresentation representation, Zone *zone) const
AbstractField(Node *object, FieldInfo info, Zone *zone)
AbstractField const * Merge(AbstractField const *that, Zone *zone, int *count) const
AbstractField const * Extend(Node *object, FieldInfo info, Zone *zone, int current_field_count) const
ZoneMap< Node *, ZoneRefSet< Map > > info_for_node_
std::array< AbstractField const *, kMaxTrackedFieldsPerObject > AbstractFields
bool operator==(const IndexRange &other) const
bool operator!=(const IndexRange &other) const
AbstractStateForEffectNodes node_states_
LoadElimination(Editor *editor, JSHeapBroker *broker, JSGraph *jsgraph, Zone *zone)
static AbstractState const * empty_state()
JSHeapBroker *const broker_
const v8::base::TimeTicks end_
Definition sweeper.cc:54
Handle< SharedFunctionInfo > info
Isolate * isolate
JSHeapBroker * broker
int32_t offset
Handle< FixedArray > elements_
Definition isolate.cc:1119
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
Definition graph.h:1231
Node::Uses::const_iterator begin(const Node::Uses &uses)
Definition node.h:708
#define NON_EXPORTED_BASE(code)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define arraysize(array)
Definition macros.h:67
Element(Node *object, Node *index, Node *value, MachineRepresentation representation)
bool operator==(const FieldInfo &other) const
FieldInfo(Node *value, MachineRepresentation representation, MaybeHandle< Name > name={}, ConstFieldInfo const_field_info=ConstFieldInfo::None())
bool operator!=(const FieldInfo &other) const