OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/load-elimination.h" | 5 #include "src/compiler/load-elimination.h" |
6 | 6 |
7 #include "src/compiler/js-graph.h" | 7 #include "src/compiler/js-graph.h" |
8 #include "src/compiler/node-properties.h" | 8 #include "src/compiler/node-properties.h" |
9 #include "src/compiler/simplified-operator.h" | 9 #include "src/compiler/simplified-operator.h" |
10 | 10 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 } | 48 } |
49 | 49 |
50 bool MayAlias(Node* a, Node* b) { return QueryAlias(a, b) != kNoAlias; } | 50 bool MayAlias(Node* a, Node* b) { return QueryAlias(a, b) != kNoAlias; } |
51 | 51 |
52 bool MustAlias(Node* a, Node* b) { return QueryAlias(a, b) == kMustAlias; } | 52 bool MustAlias(Node* a, Node* b) { return QueryAlias(a, b) == kMustAlias; } |
53 | 53 |
54 } // namespace | 54 } // namespace |
55 | 55 |
56 Reduction LoadElimination::Reduce(Node* node) { | 56 Reduction LoadElimination::Reduce(Node* node) { |
57 switch (node->opcode()) { | 57 switch (node->opcode()) { |
| 58 case IrOpcode::kArrayBufferWasNeutered: |
| 59 return ReduceArrayBufferWasNeutered(node); |
58 case IrOpcode::kCheckMaps: | 60 case IrOpcode::kCheckMaps: |
59 return ReduceCheckMaps(node); | 61 return ReduceCheckMaps(node); |
60 case IrOpcode::kEnsureWritableFastElements: | 62 case IrOpcode::kEnsureWritableFastElements: |
61 return ReduceEnsureWritableFastElements(node); | 63 return ReduceEnsureWritableFastElements(node); |
62 case IrOpcode::kMaybeGrowFastElements: | 64 case IrOpcode::kMaybeGrowFastElements: |
63 return ReduceMaybeGrowFastElements(node); | 65 return ReduceMaybeGrowFastElements(node); |
64 case IrOpcode::kTransitionElementsKind: | 66 case IrOpcode::kTransitionElementsKind: |
65 return ReduceTransitionElementsKind(node); | 67 return ReduceTransitionElementsKind(node); |
66 case IrOpcode::kLoadField: | 68 case IrOpcode::kLoadField: |
67 return ReduceLoadField(node); | 69 return ReduceLoadField(node); |
(...skipping 10 matching lines...) Expand all Loading... |
78 case IrOpcode::kDead: | 80 case IrOpcode::kDead: |
79 break; | 81 break; |
80 case IrOpcode::kStart: | 82 case IrOpcode::kStart: |
81 return ReduceStart(node); | 83 return ReduceStart(node); |
82 default: | 84 default: |
83 return ReduceOtherNode(node); | 85 return ReduceOtherNode(node); |
84 } | 86 } |
85 return NoChange(); | 87 return NoChange(); |
86 } | 88 } |
87 | 89 |
| 90 namespace { |
| 91 |
| 92 bool IsCompatibleCheck(Node const* a, Node const* b) { |
| 93 if (a->op() != b->op()) return false; |
| 94 for (int i = a->op()->ValueInputCount(); --i >= 0;) { |
| 95 if (!MustAlias(a->InputAt(i), b->InputAt(i))) return false; |
| 96 } |
| 97 return true; |
| 98 } |
| 99 |
| 100 } // namespace |
| 101 |
| 102 Node* LoadElimination::AbstractChecks::Lookup(Node* node) const { |
| 103 for (Node* const check : nodes_) { |
| 104 if (check && IsCompatibleCheck(check, node)) { |
| 105 return check; |
| 106 } |
| 107 } |
| 108 return nullptr; |
| 109 } |
| 110 |
| 111 bool LoadElimination::AbstractChecks::Equals(AbstractChecks const* that) const { |
| 112 if (this == that) return true; |
| 113 for (size_t i = 0; i < arraysize(nodes_); ++i) { |
| 114 if (Node* this_node = this->nodes_[i]) { |
| 115 for (size_t j = 0;; ++j) { |
| 116 if (j == arraysize(nodes_)) return false; |
| 117 if (that->nodes_[j] == this_node) break; |
| 118 } |
| 119 } |
| 120 } |
| 121 for (size_t i = 0; i < arraysize(nodes_); ++i) { |
| 122 if (Node* that_node = that->nodes_[i]) { |
| 123 for (size_t j = 0;; ++j) { |
| 124 if (j == arraysize(nodes_)) return false; |
| 125 if (this->nodes_[j] == that_node) break; |
| 126 } |
| 127 } |
| 128 } |
| 129 return true; |
| 130 } |
| 131 |
| 132 LoadElimination::AbstractChecks const* LoadElimination::AbstractChecks::Merge( |
| 133 AbstractChecks const* that, Zone* zone) const { |
| 134 if (this->Equals(that)) return this; |
| 135 AbstractChecks* copy = new (zone) AbstractChecks(zone); |
| 136 for (Node* const this_node : this->nodes_) { |
| 137 if (this_node == nullptr) continue; |
| 138 for (Node* const that_node : that->nodes_) { |
| 139 if (this_node == that_node) { |
| 140 copy->nodes_[copy->next_index_++] = this_node; |
| 141 break; |
| 142 } |
| 143 } |
| 144 } |
| 145 copy->next_index_ %= arraysize(nodes_); |
| 146 return copy; |
| 147 } |
| 148 |
88 Node* LoadElimination::AbstractElements::Lookup(Node* object, | 149 Node* LoadElimination::AbstractElements::Lookup(Node* object, |
89 Node* index) const { | 150 Node* index) const { |
90 for (Element const element : elements_) { | 151 for (Element const element : elements_) { |
91 if (element.object == nullptr) continue; | 152 if (element.object == nullptr) continue; |
92 DCHECK_NOT_NULL(element.index); | 153 DCHECK_NOT_NULL(element.index); |
93 DCHECK_NOT_NULL(element.value); | 154 DCHECK_NOT_NULL(element.value); |
94 if (MustAlias(object, element.object) && MustAlias(index, element.index)) { | 155 if (MustAlias(object, element.object) && MustAlias(index, element.index)) { |
95 return element.value; | 156 return element.value; |
96 } | 157 } |
97 } | 158 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 Zone* zone) const { | 219 Zone* zone) const { |
159 if (this->Equals(that)) return this; | 220 if (this->Equals(that)) return this; |
160 AbstractElements* copy = new (zone) AbstractElements(zone); | 221 AbstractElements* copy = new (zone) AbstractElements(zone); |
161 for (Element const this_element : this->elements_) { | 222 for (Element const this_element : this->elements_) { |
162 if (this_element.object == nullptr) continue; | 223 if (this_element.object == nullptr) continue; |
163 for (Element const that_element : that->elements_) { | 224 for (Element const that_element : that->elements_) { |
164 if (this_element.object == that_element.object && | 225 if (this_element.object == that_element.object && |
165 this_element.index == that_element.index && | 226 this_element.index == that_element.index && |
166 this_element.value == that_element.value) { | 227 this_element.value == that_element.value) { |
167 copy->elements_[copy->next_index_++] = this_element; | 228 copy->elements_[copy->next_index_++] = this_element; |
| 229 break; |
168 } | 230 } |
169 } | 231 } |
170 } | 232 } |
171 copy->next_index_ %= arraysize(elements_); | 233 copy->next_index_ %= arraysize(elements_); |
172 return copy; | 234 return copy; |
173 } | 235 } |
174 | 236 |
175 Node* LoadElimination::AbstractField::Lookup(Node* object) const { | 237 Node* LoadElimination::AbstractField::Lookup(Node* object) const { |
176 for (auto pair : info_for_node_) { | 238 for (auto pair : info_for_node_) { |
177 if (MustAlias(object, pair.first)) return pair.second; | 239 if (MustAlias(object, pair.first)) return pair.second; |
178 } | 240 } |
179 return nullptr; | 241 return nullptr; |
180 } | 242 } |
181 | 243 |
182 LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill( | 244 LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill( |
183 Node* object, Zone* zone) const { | 245 Node* object, Zone* zone) const { |
184 for (auto pair : this->info_for_node_) { | 246 for (auto pair : this->info_for_node_) { |
185 if (MayAlias(object, pair.first)) { | 247 if (MayAlias(object, pair.first)) { |
186 AbstractField* that = new (zone) AbstractField(zone); | 248 AbstractField* that = new (zone) AbstractField(zone); |
187 for (auto pair : this->info_for_node_) { | 249 for (auto pair : this->info_for_node_) { |
188 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); | 250 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair); |
189 } | 251 } |
190 return that; | 252 return that; |
191 } | 253 } |
192 } | 254 } |
193 return this; | 255 return this; |
194 } | 256 } |
195 | 257 |
196 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { | 258 bool LoadElimination::AbstractState::Equals(AbstractState const* that) const { |
| 259 if (this->checks_) { |
| 260 if (!that->checks_ || !that->checks_->Equals(this->checks_)) { |
| 261 return false; |
| 262 } |
| 263 } else if (that->checks_) { |
| 264 return false; |
| 265 } |
197 if (this->elements_) { | 266 if (this->elements_) { |
198 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { | 267 if (!that->elements_ || !that->elements_->Equals(this->elements_)) { |
199 return false; | 268 return false; |
200 } | 269 } |
201 } else if (that->elements_) { | 270 } else if (that->elements_) { |
202 return false; | 271 return false; |
203 } | 272 } |
204 for (size_t i = 0u; i < arraysize(fields_); ++i) { | 273 for (size_t i = 0u; i < arraysize(fields_); ++i) { |
205 AbstractField const* this_field = this->fields_[i]; | 274 AbstractField const* this_field = this->fields_[i]; |
206 AbstractField const* that_field = that->fields_[i]; | 275 AbstractField const* that_field = that->fields_[i]; |
207 if (this_field) { | 276 if (this_field) { |
208 if (!that_field || !that_field->Equals(this_field)) return false; | 277 if (!that_field || !that_field->Equals(this_field)) return false; |
209 } else if (that_field) { | 278 } else if (that_field) { |
210 return false; | 279 return false; |
211 } | 280 } |
212 } | 281 } |
213 return true; | 282 return true; |
214 } | 283 } |
215 | 284 |
216 void LoadElimination::AbstractState::Merge(AbstractState const* that, | 285 void LoadElimination::AbstractState::Merge(AbstractState const* that, |
217 Zone* zone) { | 286 Zone* zone) { |
| 287 // Merge the information we have about the checks. |
| 288 if (this->checks_) { |
| 289 this->checks_ = |
| 290 that->checks_ ? that->checks_->Merge(this->checks_, zone) : nullptr; |
| 291 } |
| 292 |
218 // Merge the information we have about the elements. | 293 // Merge the information we have about the elements. |
219 if (this->elements_) { | 294 if (this->elements_) { |
220 this->elements_ = that->elements_ | 295 this->elements_ = that->elements_ |
221 ? that->elements_->Merge(this->elements_, zone) | 296 ? that->elements_->Merge(this->elements_, zone) |
222 : nullptr; | 297 : nullptr; |
223 } | 298 } |
224 | 299 |
225 // Merge the information we have about the fields. | 300 // Merge the information we have about the fields. |
226 for (size_t i = 0; i < arraysize(fields_); ++i) { | 301 for (size_t i = 0; i < arraysize(fields_); ++i) { |
227 if (this->fields_[i]) { | 302 if (this->fields_[i]) { |
228 if (that->fields_[i]) { | 303 if (that->fields_[i]) { |
229 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); | 304 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone); |
230 } else { | 305 } else { |
231 this->fields_[i] = nullptr; | 306 this->fields_[i] = nullptr; |
232 } | 307 } |
233 } | 308 } |
234 } | 309 } |
235 } | 310 } |
236 | 311 |
| 312 Node* LoadElimination::AbstractState::LookupCheck(Node* node) const { |
| 313 return this->checks_ ? this->checks_->Lookup(node) : nullptr; |
| 314 } |
| 315 |
| 316 LoadElimination::AbstractState const* LoadElimination::AbstractState::AddCheck( |
| 317 Node* node, Zone* zone) const { |
| 318 AbstractState* that = new (zone) AbstractState(*this); |
| 319 if (that->checks_) { |
| 320 that->checks_ = that->checks_->Extend(node, zone); |
| 321 } else { |
| 322 that->checks_ = new (zone) AbstractChecks(node, zone); |
| 323 } |
| 324 return that; |
| 325 } |
| 326 |
237 Node* LoadElimination::AbstractState::LookupElement(Node* object, | 327 Node* LoadElimination::AbstractState::LookupElement(Node* object, |
238 Node* index) const { | 328 Node* index) const { |
239 if (this->elements_) { | 329 if (this->elements_) { |
240 return this->elements_->Lookup(object, index); | 330 return this->elements_->Lookup(object, index); |
241 } | 331 } |
242 return nullptr; | 332 return nullptr; |
243 } | 333 } |
244 | 334 |
245 LoadElimination::AbstractState const* | 335 LoadElimination::AbstractState const* |
246 LoadElimination::AbstractState::AddElement(Node* object, Node* index, | 336 LoadElimination::AbstractState::AddElement(Node* object, Node* index, |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 return nullptr; | 398 return nullptr; |
309 } | 399 } |
310 | 400 |
311 void LoadElimination::AbstractStateForEffectNodes::Set( | 401 void LoadElimination::AbstractStateForEffectNodes::Set( |
312 Node* node, AbstractState const* state) { | 402 Node* node, AbstractState const* state) { |
313 size_t const id = node->id(); | 403 size_t const id = node->id(); |
314 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); | 404 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr); |
315 info_for_node_[id] = state; | 405 info_for_node_[id] = state; |
316 } | 406 } |
317 | 407 |
| 408 Reduction LoadElimination::ReduceArrayBufferWasNeutered(Node* node) { |
| 409 Node* const effect = NodeProperties::GetEffectInput(node); |
| 410 AbstractState const* state = node_states_.Get(effect); |
| 411 if (state == nullptr) return NoChange(); |
| 412 if (Node* const check = state->LookupCheck(node)) { |
| 413 ReplaceWithValue(node, check, effect); |
| 414 return Replace(check); |
| 415 } |
| 416 state = state->AddCheck(node, zone()); |
| 417 return UpdateState(node, state); |
| 418 } |
| 419 |
318 Reduction LoadElimination::ReduceCheckMaps(Node* node) { | 420 Reduction LoadElimination::ReduceCheckMaps(Node* node) { |
319 Node* const object = NodeProperties::GetValueInput(node, 0); | 421 Node* const object = NodeProperties::GetValueInput(node, 0); |
320 Node* const effect = NodeProperties::GetEffectInput(node); | 422 Node* const effect = NodeProperties::GetEffectInput(node); |
321 AbstractState const* state = node_states_.Get(effect); | 423 AbstractState const* state = node_states_.Get(effect); |
322 if (state == nullptr) return NoChange(); | 424 if (state == nullptr) return NoChange(); |
323 int const map_input_count = node->op()->ValueInputCount() - 1; | 425 int const map_input_count = node->op()->ValueInputCount() - 1; |
324 if (Node* const object_map = state->LookupField(object, 0)) { | 426 if (Node* const object_map = state->LookupField(object, 0)) { |
325 for (int i = 0; i < map_input_count; ++i) { | 427 for (int i = 0; i < map_input_count; ++i) { |
326 Node* map = NodeProperties::GetValueInput(node, 1 + i); | 428 Node* map = NodeProperties::GetValueInput(node, 1 + i); |
327 if (map == object_map) return Replace(effect); | 429 if (map == object_map) return Replace(effect); |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
699 DCHECK_EQ(kTaggedBase, access.base_is_tagged); | 801 DCHECK_EQ(kTaggedBase, access.base_is_tagged); |
700 DCHECK_EQ(0, access.offset % kPointerSize); | 802 DCHECK_EQ(0, access.offset % kPointerSize); |
701 int field_index = access.offset / kPointerSize; | 803 int field_index = access.offset / kPointerSize; |
702 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; | 804 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1; |
703 return field_index; | 805 return field_index; |
704 } | 806 } |
705 | 807 |
706 } // namespace compiler | 808 } // namespace compiler |
707 } // namespace internal | 809 } // namespace internal |
708 } // namespace v8 | 810 } // namespace v8 |
OLD | NEW |