OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
6 | 6 |
| 7 #include <limits> |
| 8 |
7 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
8 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
9 #include "src/compilation-dependencies.h" | 11 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/common-operator.h" | 12 #include "src/compiler/common-operator.h" |
11 #include "src/compiler/graph-reducer.h" | 13 #include "src/compiler/graph-reducer.h" |
12 #include "src/compiler/js-operator.h" | 14 #include "src/compiler/js-operator.h" |
13 #include "src/compiler/node.h" | 15 #include "src/compiler/node.h" |
14 #include "src/compiler/node-matchers.h" | 16 #include "src/compiler/node-matchers.h" |
15 #include "src/compiler/node-properties.h" | 17 #include "src/compiler/node-properties.h" |
| 18 #include "src/compiler/operator-properties.h" |
16 #include "src/compiler/simplified-operator.h" | 19 #include "src/compiler/simplified-operator.h" |
17 #include "src/objects-inl.h" | 20 #include "src/objects-inl.h" |
18 #include "src/type-cache.h" | 21 #include "src/type-cache.h" |
19 | 22 |
20 namespace v8 { | 23 namespace v8 { |
21 namespace internal { | 24 namespace internal { |
22 namespace compiler { | 25 namespace compiler { |
23 | 26 |
| 27 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable = |
| 28 std::numeric_limits<Alias>::max(); |
| 29 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable = |
| 30 std::numeric_limits<Alias>::max() - 1; |
| 31 |
| 32 |
24 class VirtualObject : public ZoneObject { | 33 class VirtualObject : public ZoneObject { |
25 public: | 34 public: |
26 enum Status { kUntracked = 0, kTracked = 1 }; | 35 enum Status { kUntracked = 0, kTracked = 1 }; |
27 VirtualObject(NodeId id, Zone* zone) | 36 VirtualObject(NodeId id, Zone* zone) |
28 : id_(id), | 37 : id_(id), |
29 status_(kUntracked), | 38 status_(kUntracked), |
30 fields_(zone), | 39 fields_(zone), |
31 phi_(zone), | 40 phi_(zone), |
32 object_state_(nullptr) {} | 41 object_state_(nullptr) {} |
33 | 42 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
91 if (fields_[i] != nullptr) { | 100 if (fields_[i] != nullptr) { |
92 fields_[i] = nullptr; | 101 fields_[i] = nullptr; |
93 changed = true; | 102 changed = true; |
94 } | 103 } |
95 phi_[i] = false; | 104 phi_[i] = false; |
96 } | 105 } |
97 return changed; | 106 return changed; |
98 } | 107 } |
99 bool UpdateFrom(const VirtualObject& other); | 108 bool UpdateFrom(const VirtualObject& other); |
100 void SetObjectState(Node* node) { object_state_ = node; } | 109 void SetObjectState(Node* node) { object_state_ = node; } |
101 Node* GetObjectState() { return object_state_; } | 110 Node* GetObjectState() const { return object_state_; } |
102 | 111 |
103 NodeId id() { return id_; } | 112 NodeId id() const { return id_; } |
104 void id(NodeId id) { id_ = id; } | 113 void id(NodeId id) { id_ = id; } |
105 | 114 |
106 private: | 115 private: |
107 NodeId id_; | 116 NodeId id_; |
108 Status status_; | 117 Status status_; |
109 ZoneVector<Node*> fields_; | 118 ZoneVector<Node*> fields_; |
110 ZoneVector<bool> phi_; | 119 ZoneVector<bool> phi_; |
111 Node* object_state_; | 120 Node* object_state_; |
112 }; | 121 }; |
113 | 122 |
(...skipping 13 matching lines...) Expand all Loading... |
127 } | 136 } |
128 return changed; | 137 return changed; |
129 } | 138 } |
130 | 139 |
131 | 140 |
132 class VirtualState : public ZoneObject { | 141 class VirtualState : public ZoneObject { |
133 public: | 142 public: |
134 VirtualState(Zone* zone, size_t size); | 143 VirtualState(Zone* zone, size_t size); |
135 VirtualState(const VirtualState& states); | 144 VirtualState(const VirtualState& states); |
136 | 145 |
137 VirtualObject* GetVirtualObject(Node* node); | 146 VirtualObject* VirtualObjectFromAlias(size_t alias); |
138 VirtualObject* GetVirtualObject(size_t id); | 147 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias, |
139 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); | 148 NodeId id, Zone* zone); |
140 void SetVirtualObject(NodeId id, VirtualObject* state); | 149 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state); |
141 void LastChangedAt(Node* node) { last_changed_ = node; } | 150 void LastChangedAt(Node* node) { last_changed_ = node; } |
142 Node* GetLastChanged() { return last_changed_; } | 151 Node* GetLastChanged() { return last_changed_; } |
143 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); | |
144 bool UpdateFrom(VirtualState* state, Zone* zone); | 152 bool UpdateFrom(VirtualState* state, Zone* zone); |
145 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 153 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
146 CommonOperatorBuilder* common, Node* control); | 154 CommonOperatorBuilder* common, Node* control); |
147 | 155 size_t size() const { return info_.size(); } |
148 size_t size() { return info_.size(); } | |
149 | 156 |
150 private: | 157 private: |
151 ZoneVector<VirtualObject*> info_; | 158 ZoneVector<VirtualObject*> info_; |
152 Node* last_changed_; | 159 Node* last_changed_; |
153 }; | 160 }; |
154 | 161 |
155 | 162 |
156 class MergeCache : public ZoneObject { | 163 class MergeCache : public ZoneObject { |
157 public: | 164 public: |
158 explicit MergeCache(Zone* zone) | 165 explicit MergeCache(Zone* zone) |
159 : states_(zone), objects_(zone), fields_(zone), min_size_(SIZE_MAX) { | 166 : states_(zone), objects_(zone), fields_(zone) { |
160 states_.reserve(4); | 167 states_.reserve(4); |
161 objects_.reserve(4); | 168 objects_.reserve(4); |
162 fields_.reserve(4); | 169 fields_.reserve(4); |
163 } | 170 } |
164 ZoneVector<VirtualState*>& states() { return states_; } | 171 ZoneVector<VirtualState*>& states() { return states_; } |
165 ZoneVector<VirtualObject*>& objects() { return objects_; } | 172 ZoneVector<VirtualObject*>& objects() { return objects_; } |
166 ZoneVector<Node*>& fields() { return fields_; } | 173 ZoneVector<Node*>& fields() { return fields_; } |
167 void Clear() { | 174 void Clear() { |
168 states_.clear(); | 175 states_.clear(); |
169 objects_.clear(); | 176 objects_.clear(); |
170 fields_.clear(); | 177 fields_.clear(); |
171 min_size_ = SIZE_MAX; | |
172 } | 178 } |
173 void push_back(VirtualState* state) { | 179 size_t LoadVirtualObjectsFromStatesFor(EscapeAnalysis::Alias alias); |
174 states_.push_back(state); | 180 void LoadVirtualObjectsForFieldsFrom( |
175 min_size_ = std::min(state->size(), min_size_); | 181 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases); |
176 } | |
177 size_t min_size() { return min_size_; } | |
178 | |
179 size_t LoadVirtualObjectsFromStatesFor(NodeId id); | |
180 void LoadVirtualObjectsForFieldsFrom(VirtualState* state); | |
181 Node* GetFields(size_t pos); | 182 Node* GetFields(size_t pos); |
182 | 183 |
183 private: | 184 private: |
184 ZoneVector<VirtualState*> states_; | 185 ZoneVector<VirtualState*> states_; |
185 ZoneVector<VirtualObject*> objects_; | 186 ZoneVector<VirtualObject*> objects_; |
186 ZoneVector<Node*> fields_; | 187 ZoneVector<Node*> fields_; |
187 size_t min_size_; | |
188 }; | 188 }; |
189 | 189 |
190 | 190 |
191 size_t MergeCache::LoadVirtualObjectsFromStatesFor(NodeId id) { | 191 size_t MergeCache::LoadVirtualObjectsFromStatesFor( |
| 192 EscapeAnalysis::Alias alias) { |
192 objects_.clear(); | 193 objects_.clear(); |
193 DCHECK_GT(states_.size(), 0u); | 194 DCHECK_GT(states_.size(), 0u); |
194 size_t min = SIZE_MAX; | 195 size_t min = std::numeric_limits<size_t>::max(); |
195 for (VirtualState* state : states_) { | 196 for (VirtualState* state : states_) { |
196 if (VirtualObject* obj = state->GetVirtualObject(id)) { | 197 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
197 objects_.push_back(obj); | 198 objects_.push_back(obj); |
198 min = std::min(obj->field_count(), min); | 199 min = std::min(obj->field_count(), min); |
199 } | 200 } |
200 } | 201 } |
201 return min; | 202 return min; |
202 } | 203 } |
203 | 204 |
204 | 205 |
205 void MergeCache::LoadVirtualObjectsForFieldsFrom(VirtualState* state) { | 206 void MergeCache::LoadVirtualObjectsForFieldsFrom( |
| 207 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases) { |
206 objects_.clear(); | 208 objects_.clear(); |
| 209 size_t max_alias = state->size(); |
207 for (Node* field : fields_) { | 210 for (Node* field : fields_) { |
208 if (VirtualObject* obj = state->GetVirtualObject(field)) { | 211 EscapeAnalysis::Alias alias = aliases[field->id()]; |
| 212 if (alias >= max_alias) continue; |
| 213 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
209 objects_.push_back(obj); | 214 objects_.push_back(obj); |
210 } | 215 } |
211 } | 216 } |
212 } | 217 } |
213 | 218 |
214 | 219 |
215 Node* MergeCache::GetFields(size_t pos) { | 220 Node* MergeCache::GetFields(size_t pos) { |
216 fields_.clear(); | 221 fields_.clear(); |
217 Node* rep = objects_.front()->GetField(pos); | 222 Node* rep = objects_.front()->GetField(pos); |
218 for (VirtualObject* obj : objects_) { | 223 for (VirtualObject* obj : objects_) { |
(...skipping 10 matching lines...) Expand all Loading... |
229 | 234 |
230 | 235 |
231 VirtualState::VirtualState(Zone* zone, size_t size) | 236 VirtualState::VirtualState(Zone* zone, size_t size) |
232 : info_(size, nullptr, zone), last_changed_(nullptr) {} | 237 : info_(size, nullptr, zone), last_changed_(nullptr) {} |
233 | 238 |
234 | 239 |
235 VirtualState::VirtualState(const VirtualState& state) | 240 VirtualState::VirtualState(const VirtualState& state) |
236 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | 241 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
237 last_changed_(state.last_changed_) { | 242 last_changed_(state.last_changed_) { |
238 for (size_t i = 0; i < state.info_.size(); ++i) { | 243 for (size_t i = 0; i < state.info_.size(); ++i) { |
239 if (state.info_[i] && state.info_[i]->id() == i) { | 244 if (state.info_[i]) { |
240 info_[i] = new (state.info_.get_allocator().zone()) | 245 info_[i] = |
241 VirtualObject(*state.info_[i]); | 246 new (info_.get_allocator().zone()) VirtualObject(*state.info_[i]); |
242 } | |
243 } | |
244 for (size_t i = 0; i < state.info_.size(); ++i) { | |
245 if (state.info_[i] && state.info_[i]->id() != i) { | |
246 info_[i] = info_[state.info_[i]->id()]; | |
247 } | 247 } |
248 } | 248 } |
249 } | 249 } |
250 | 250 |
251 | 251 |
252 VirtualObject* VirtualState::GetVirtualObject(size_t id) { | 252 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
253 if (id >= info_.size()) return nullptr; | 253 return info_[alias]; |
254 return info_[id]; | |
255 } | 254 } |
256 | 255 |
257 | 256 |
258 VirtualObject* VirtualState::GetVirtualObject(Node* node) { | 257 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
259 return GetVirtualObject(node->id()); | 258 EscapeAnalysis::Alias alias, NodeId id, Zone* zone) { |
260 } | 259 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
261 | |
262 | |
263 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, | |
264 Zone* zone) { | |
265 if (VirtualObject* obj = GetVirtualObject(id)) { | |
266 return obj; | 260 return obj; |
267 } | 261 } |
268 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 262 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); |
269 SetVirtualObject(id, obj); | 263 SetVirtualObject(alias, obj); |
270 return obj; | 264 return obj; |
271 } | 265 } |
272 | 266 |
273 | 267 |
274 void VirtualState::SetVirtualObject(NodeId id, VirtualObject* obj) { | 268 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias, |
275 info_[id] = obj; | 269 VirtualObject* obj) { |
276 } | 270 info_[alias] = obj; |
277 | |
278 | |
279 bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) { | |
280 VirtualObject* obj = GetVirtualObject(id); | |
281 if (!obj) { | |
282 obj = new (zone) VirtualObject(*fromObj); | |
283 SetVirtualObject(id, obj); | |
284 if (FLAG_trace_turbo_escape) { | |
285 PrintF(" Taking field for #%d from %p\n", id, | |
286 static_cast<void*>(fromObj)); | |
287 } | |
288 return true; | |
289 } | |
290 | |
291 if (obj->UpdateFrom(*fromObj)) { | |
292 if (FLAG_trace_turbo_escape) { | |
293 PrintF(" Updating field for #%d from %p\n", id, | |
294 static_cast<void*>(fromObj)); | |
295 } | |
296 return true; | |
297 } | |
298 | |
299 return false; | |
300 } | 271 } |
301 | 272 |
302 | 273 |
303 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 274 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { |
304 bool changed = false; | 275 bool changed = false; |
305 for (NodeId id = 0; id < size(); ++id) { | 276 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
306 VirtualObject* ls = GetVirtualObject(id); | 277 VirtualObject* ls = VirtualObjectFromAlias(alias); |
307 VirtualObject* rs = from->GetVirtualObject(id); | 278 VirtualObject* rs = from->VirtualObjectFromAlias(alias); |
308 | 279 |
309 if (rs == nullptr) { | 280 if (rs == nullptr) { |
310 continue; | 281 continue; |
311 } | 282 } |
312 | 283 |
313 if (ls == nullptr) { | 284 if (ls == nullptr) { |
314 ls = new (zone) VirtualObject(*rs); | 285 ls = new (zone) VirtualObject(*rs); |
315 SetVirtualObject(id, ls); | 286 SetVirtualObject(alias, ls); |
316 changed = true; | 287 changed = true; |
317 continue; | 288 continue; |
318 } | 289 } |
319 | 290 |
320 if (FLAG_trace_turbo_escape) { | 291 if (FLAG_trace_turbo_escape) { |
321 PrintF(" Updating fields of #%d\n", id); | 292 PrintF(" Updating fields of @%d\n", alias); |
322 } | 293 } |
323 | 294 |
324 changed = ls->UpdateFrom(*rs) || changed; | 295 changed = ls->UpdateFrom(*rs) || changed; |
325 } | 296 } |
326 return false; | 297 return false; |
327 } | 298 } |
328 | 299 |
329 | 300 |
330 namespace { | 301 namespace { |
331 | 302 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 } | 342 } |
372 } | 343 } |
373 return rep; | 344 return rep; |
374 } | 345 } |
375 | 346 |
376 | 347 |
377 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 348 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
378 CommonOperatorBuilder* common, Node* control) { | 349 CommonOperatorBuilder* common, Node* control) { |
379 DCHECK_GT(cache->states().size(), 0u); | 350 DCHECK_GT(cache->states().size(), 0u); |
380 bool changed = false; | 351 bool changed = false; |
381 for (NodeId id = 0; id < cache->min_size(); ++id) { | 352 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) { |
382 size_t fields = cache->LoadVirtualObjectsFromStatesFor(id); | 353 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias); |
383 if (cache->objects().size() == cache->states().size()) { | 354 if (cache->objects().size() == cache->states().size()) { |
384 // Don't process linked objects. | |
385 if (cache->objects()[0]->id() != id) continue; | |
386 if (FLAG_trace_turbo_escape) { | 355 if (FLAG_trace_turbo_escape) { |
387 PrintF(" Merging virtual objects of #%d\n", id); | 356 PrintF(" Merging virtual objects of @%d\n", alias); |
388 } | 357 } |
389 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); | 358 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject( |
| 359 alias, cache->objects().front()->id(), zone); |
390 changed = mergeObject->ResizeFields(fields) || changed; | 360 changed = mergeObject->ResizeFields(fields) || changed; |
391 for (size_t i = 0; i < fields; ++i) { | 361 for (size_t i = 0; i < fields; ++i) { |
392 if (Node* field = cache->GetFields(i)) { | 362 if (Node* field = cache->GetFields(i)) { |
393 changed = mergeObject->SetField(i, field) || changed; | 363 changed = mergeObject->SetField(i, field) || changed; |
394 if (FLAG_trace_turbo_escape) { | 364 if (FLAG_trace_turbo_escape) { |
395 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); | 365 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); |
396 } | 366 } |
397 } else { | 367 } else { |
398 int value_input_count = static_cast<int>(cache->fields().size()); | 368 int value_input_count = static_cast<int>(cache->fields().size()); |
399 if (cache->fields().size() == cache->objects().size()) { | 369 if (cache->fields().size() == cache->objects().size()) { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 rep, common->Phi(MachineRepresentation::kTagged, | 408 rep, common->Phi(MachineRepresentation::kTagged, |
439 value_input_count)); | 409 value_input_count)); |
440 } | 410 } |
441 } | 411 } |
442 } else { | 412 } else { |
443 changed = mergeObject->SetField(i, nullptr) || changed; | 413 changed = mergeObject->SetField(i, nullptr) || changed; |
444 } | 414 } |
445 } | 415 } |
446 } | 416 } |
447 } else { | 417 } else { |
448 SetVirtualObject(id, nullptr); | 418 SetVirtualObject(alias, nullptr); |
449 } | |
450 } | |
451 // Update linked objects. | |
452 for (NodeId id = 0; id < cache->min_size(); ++id) { | |
453 if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) { | |
454 if (obj->id() != id) { | |
455 SetVirtualObject(id, GetVirtualObject(obj->id())); | |
456 } | |
457 } | 419 } |
458 } | 420 } |
459 return changed; | 421 return changed; |
460 } | 422 } |
461 | 423 |
462 | 424 |
463 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 425 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
464 Graph* graph, Zone* zone) | 426 Graph* graph, Zone* zone) |
465 : object_analysis_(object_analysis), | 427 : object_analysis_(object_analysis), |
466 graph_(graph), | 428 graph_(graph), |
467 zone_(zone), | 429 zone_(zone), |
468 info_(graph->NodeCount(), kUnknown, zone), | 430 status_(graph->NodeCount(), kUnknown, zone), |
469 queue_(zone) {} | 431 queue_(zone) {} |
470 | 432 |
471 | 433 |
472 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 434 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
473 | 435 |
474 | 436 |
475 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 437 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
476 return info_[node->id()] != kUnknown; | 438 return status_[node->id()] & (kTracked | kEscaped); |
477 } | 439 } |
478 | 440 |
479 | 441 |
480 bool EscapeStatusAnalysis::IsVirtual(Node* node) { | 442 bool EscapeStatusAnalysis::IsVirtual(Node* node) { |
481 return info_[node->id()] == kVirtual; | 443 return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped); |
482 } | 444 } |
483 | 445 |
484 | 446 |
485 bool EscapeStatusAnalysis::IsEscaped(Node* node) { | 447 bool EscapeStatusAnalysis::IsEscaped(Node* node) { |
486 return info_[node->id()] == kEscaped; | 448 return status_[node->id()] & kEscaped; |
487 } | 449 } |
488 | 450 |
489 | 451 |
490 bool EscapeStatusAnalysis::IsAllocation(Node* node) { | 452 bool EscapeStatusAnalysis::IsAllocation(Node* node) { |
491 return node->opcode() == IrOpcode::kAllocate || | 453 return node->opcode() == IrOpcode::kAllocate || |
492 node->opcode() == IrOpcode::kFinishRegion; | 454 node->opcode() == IrOpcode::kFinishRegion; |
493 } | 455 } |
494 | 456 |
495 | 457 |
496 bool EscapeStatusAnalysis::SetEscaped(Node* node) { | 458 bool EscapeStatusAnalysis::SetEscaped(Node* node) { |
497 bool changed = info_[node->id()] != kEscaped; | 459 bool changed = !(status_[node->id()] & kEscaped); |
498 info_[node->id()] = kEscaped; | 460 status_[node->id()] |= kEscaped | kTracked; |
499 return changed; | 461 return changed; |
500 } | 462 } |
501 | 463 |
502 | 464 |
503 void EscapeStatusAnalysis::Resize() { | 465 void EscapeStatusAnalysis::Resize() { |
504 info_.resize(graph()->NodeCount(), kUnknown); | 466 status_.resize(graph()->NodeCount(), kUnknown); |
505 } | 467 } |
506 | 468 |
507 | 469 |
508 size_t EscapeStatusAnalysis::size() { return info_.size(); } | 470 size_t EscapeStatusAnalysis::size() { return status_.size(); } |
509 | 471 |
510 | 472 |
511 void EscapeStatusAnalysis::Run() { | 473 void EscapeStatusAnalysis::Run() { |
512 Resize(); | 474 Resize(); |
513 ZoneVector<bool> visited(zone()); | |
514 visited.resize(graph()->NodeCount()); | |
515 queue_.push_back(graph()->end()); | 475 queue_.push_back(graph()->end()); |
| 476 status_[graph()->end()->id()] |= kOnStack; |
516 while (!queue_.empty()) { | 477 while (!queue_.empty()) { |
517 Node* node = queue_.front(); | 478 Node* node = queue_.front(); |
518 queue_.pop_front(); | 479 queue_.pop_front(); |
| 480 status_[node->id()] &= ~kOnStack; |
519 Process(node); | 481 Process(node); |
520 if (!visited[node->id()]) { | 482 status_[node->id()] |= kVisited; |
521 RevisitInputs(node); | 483 for (Edge edge : node->input_edges()) { |
| 484 Node* input = edge.to(); |
| 485 if (!(status_[input->id()] & (kVisited | kOnStack))) { |
| 486 queue_.push_back(input); |
| 487 status_[input->id()] |= kOnStack; |
| 488 } |
522 } | 489 } |
523 visited[node->id()] = true; | |
524 } | |
525 if (FLAG_trace_turbo_escape) { | |
526 DebugPrint(); | |
527 } | 490 } |
528 } | 491 } |
529 | 492 |
530 | 493 |
531 void EscapeStatusAnalysis::RevisitInputs(Node* node) { | 494 void EscapeStatusAnalysis::RevisitInputs(Node* node) { |
532 for (Edge edge : node->input_edges()) { | 495 for (Edge edge : node->input_edges()) { |
533 Node* input = edge.to(); | 496 Node* input = edge.to(); |
534 queue_.push_back(input); | 497 if (!(status_[input->id()] & kOnStack)) { |
| 498 queue_.push_back(input); |
| 499 status_[input->id()] |= kOnStack; |
| 500 } |
535 } | 501 } |
536 } | 502 } |
537 | 503 |
538 | 504 |
539 void EscapeStatusAnalysis::RevisitUses(Node* node) { | 505 void EscapeStatusAnalysis::RevisitUses(Node* node) { |
540 for (Edge edge : node->use_edges()) { | 506 for (Edge edge : node->use_edges()) { |
541 Node* use = edge.from(); | 507 Node* use = edge.from(); |
542 queue_.push_back(use); | 508 if (!(status_[use->id()] & kOnStack)) { |
| 509 queue_.push_back(use); |
| 510 status_[use->id()] |= kOnStack; |
| 511 } |
543 } | 512 } |
544 } | 513 } |
545 | 514 |
546 | 515 |
547 void EscapeStatusAnalysis::Process(Node* node) { | 516 void EscapeStatusAnalysis::Process(Node* node) { |
548 switch (node->opcode()) { | 517 switch (node->opcode()) { |
549 case IrOpcode::kAllocate: | 518 case IrOpcode::kAllocate: |
550 ProcessAllocate(node); | 519 ProcessAllocate(node); |
551 break; | 520 break; |
552 case IrOpcode::kFinishRegion: | 521 case IrOpcode::kFinishRegion: |
(...skipping 10 matching lines...) Expand all Loading... |
563 if (Node* rep = object_analysis_->GetReplacement(node)) { | 532 if (Node* rep = object_analysis_->GetReplacement(node)) { |
564 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { | 533 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { |
565 RevisitInputs(rep); | 534 RevisitInputs(rep); |
566 RevisitUses(rep); | 535 RevisitUses(rep); |
567 } | 536 } |
568 } | 537 } |
569 break; | 538 break; |
570 } | 539 } |
571 case IrOpcode::kPhi: | 540 case IrOpcode::kPhi: |
572 if (!HasEntry(node)) { | 541 if (!HasEntry(node)) { |
573 info_[node->id()] = kVirtual; | 542 status_[node->id()] |= kTracked; |
574 if (!IsAllocationPhi(node)) { | 543 if (!IsAllocationPhi(node)) { |
575 SetEscaped(node); | 544 SetEscaped(node); |
576 RevisitUses(node); | 545 RevisitUses(node); |
577 } | 546 } |
578 } | 547 } |
579 CheckUsesForEscape(node); | 548 CheckUsesForEscape(node); |
580 default: | 549 default: |
581 break; | 550 break; |
582 } | 551 } |
583 } | 552 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
620 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 589 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", |
621 val->id(), val->op()->mnemonic(), to->id()); | 590 val->id(), val->op()->mnemonic(), to->id()); |
622 } | 591 } |
623 } | 592 } |
624 } | 593 } |
625 | 594 |
626 | 595 |
627 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 596 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
628 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 597 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
629 if (!HasEntry(node)) { | 598 if (!HasEntry(node)) { |
630 info_[node->id()] = kVirtual; | 599 status_[node->id()] |= kTracked; |
631 if (FLAG_trace_turbo_escape) { | 600 if (FLAG_trace_turbo_escape) { |
632 PrintF("Created status entry for node #%d (%s)\n", node->id(), | 601 PrintF("Created status entry for node #%d (%s)\n", node->id(), |
633 node->op()->mnemonic()); | 602 node->op()->mnemonic()); |
634 } | 603 } |
635 NumberMatcher size(node->InputAt(0)); | 604 NumberMatcher size(node->InputAt(0)); |
636 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 605 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
637 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 606 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
638 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 607 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
639 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 608 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
640 if (!size.HasValue() && SetEscaped(node)) { | 609 if (!size.HasValue() && SetEscaped(node)) { |
641 RevisitUses(node); | 610 RevisitUses(node); |
642 if (FLAG_trace_turbo_escape) { | 611 if (FLAG_trace_turbo_escape) { |
643 PrintF("Setting #%d to escaped because of non-const alloc\n", | 612 PrintF("Setting #%d to escaped because of non-const alloc\n", |
644 node->id()); | 613 node->id()); |
645 } | 614 } |
646 // This node is known to escape, uses do not have to be checked. | 615 // This node is known to escape, uses do not have to be checked. |
647 return; | 616 return; |
648 } | 617 } |
649 } | 618 } |
650 if (CheckUsesForEscape(node, true)) { | 619 if (CheckUsesForEscape(node, true)) { |
651 RevisitUses(node); | 620 RevisitUses(node); |
652 } | 621 } |
653 } | 622 } |
654 | 623 |
655 | 624 |
656 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 625 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
657 bool phi_escaping) { | 626 bool phi_escaping) { |
658 for (Edge edge : uses->use_edges()) { | 627 for (Edge edge : uses->use_edges()) { |
659 Node* use = edge.from(); | 628 Node* use = edge.from(); |
660 if (!NodeProperties::IsValueEdge(edge) && | 629 if (edge.index() >= use->op()->ValueInputCount() + |
661 !NodeProperties::IsContextEdge(edge)) | 630 OperatorProperties::GetContextInputCount(use->op())) |
662 continue; | 631 continue; |
663 switch (use->opcode()) { | 632 switch (use->opcode()) { |
| 633 case IrOpcode::kPhi: |
| 634 if (phi_escaping && SetEscaped(rep)) { |
| 635 if (FLAG_trace_turbo_escape) { |
| 636 PrintF( |
| 637 "Setting #%d (%s) to escaped because of use by phi node " |
| 638 "#%d (%s)\n", |
| 639 rep->id(), rep->op()->mnemonic(), use->id(), |
| 640 use->op()->mnemonic()); |
| 641 } |
| 642 return true; |
| 643 } |
| 644 // Fallthrough. |
664 case IrOpcode::kStoreField: | 645 case IrOpcode::kStoreField: |
665 case IrOpcode::kLoadField: | 646 case IrOpcode::kLoadField: |
666 case IrOpcode::kStoreElement: | 647 case IrOpcode::kStoreElement: |
667 case IrOpcode::kLoadElement: | 648 case IrOpcode::kLoadElement: |
668 case IrOpcode::kFrameState: | 649 case IrOpcode::kFrameState: |
669 case IrOpcode::kStateValues: | 650 case IrOpcode::kStateValues: |
670 case IrOpcode::kReferenceEqual: | 651 case IrOpcode::kReferenceEqual: |
671 case IrOpcode::kFinishRegion: | 652 case IrOpcode::kFinishRegion: |
672 case IrOpcode::kPhi: | 653 if (IsEscaped(use) && SetEscaped(rep)) { |
673 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) { | |
674 if (FLAG_trace_turbo_escape) { | 654 if (FLAG_trace_turbo_escape) { |
675 PrintF( | 655 PrintF( |
676 "Setting #%d (%s) to escaped because of use by escaping node " | 656 "Setting #%d (%s) to escaped because of use by escaping node " |
677 "#%d (%s)\n", | 657 "#%d (%s)\n", |
678 rep->id(), rep->op()->mnemonic(), use->id(), | 658 rep->id(), rep->op()->mnemonic(), use->id(), |
679 use->op()->mnemonic()); | 659 use->op()->mnemonic()); |
680 } | |
681 return true; | |
682 } | |
683 if (phi_escaping && use->opcode() == IrOpcode::kPhi && | |
684 SetEscaped(rep)) { | |
685 if (FLAG_trace_turbo_escape) { | |
686 PrintF( | |
687 "Setting #%d (%s) to escaped because of use by phi node " | |
688 "#%d (%s)\n", | |
689 rep->id(), rep->op()->mnemonic(), use->id(), | |
690 use->op()->mnemonic()); | |
691 } | 660 } |
692 return true; | 661 return true; |
693 } | 662 } |
694 break; | 663 break; |
695 case IrOpcode::kObjectIsSmi: | 664 case IrOpcode::kObjectIsSmi: |
696 if (!IsAllocation(rep) && SetEscaped(rep)) { | 665 if (!IsAllocation(rep) && SetEscaped(rep)) { |
697 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 666 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
698 rep->id(), rep->op()->mnemonic(), use->id(), | 667 rep->id(), rep->op()->mnemonic(), use->id(), |
699 use->op()->mnemonic()); | 668 use->op()->mnemonic()); |
700 return true; | 669 return true; |
(...skipping 16 matching lines...) Expand all Loading... |
717 } | 686 } |
718 } | 687 } |
719 } | 688 } |
720 return false; | 689 return false; |
721 } | 690 } |
722 | 691 |
723 | 692 |
724 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | 693 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { |
725 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 694 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
726 if (!HasEntry(node)) { | 695 if (!HasEntry(node)) { |
727 info_[node->id()] = kVirtual; | 696 status_[node->id()] |= kTracked; |
728 RevisitUses(node); | 697 RevisitUses(node); |
729 } | 698 } |
730 if (CheckUsesForEscape(node, true)) { | 699 if (CheckUsesForEscape(node, true)) { |
731 RevisitInputs(node); | 700 RevisitInputs(node); |
732 } | 701 } |
733 } | 702 } |
734 | 703 |
735 | 704 |
736 void EscapeStatusAnalysis::DebugPrint() { | 705 void EscapeStatusAnalysis::DebugPrint() { |
737 for (NodeId id = 0; id < info_.size(); id++) { | 706 for (NodeId id = 0; id < status_.size(); id++) { |
738 if (info_[id] != kUnknown) { | 707 if (status_[id] & kTracked) { |
739 PrintF("Node #%d is %s\n", id, | 708 PrintF("Node #%d is %s\n", id, |
740 info_[id] == kEscaped ? "escaping" : "virtual"); | 709 (status_[id] & kEscaped) ? "escaping" : "virtual"); |
741 } | 710 } |
742 } | 711 } |
743 } | 712 } |
744 | 713 |
745 | 714 |
746 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 715 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
747 Zone* zone) | 716 Zone* zone) |
748 : graph_(graph), | 717 : graph_(graph), |
749 common_(common), | 718 common_(common), |
750 zone_(zone), | 719 zone_(zone), |
751 virtual_states_(zone), | 720 virtual_states_(zone), |
752 replacements_(zone), | 721 replacements_(zone), |
753 escape_status_(this, graph, zone), | 722 escape_status_(this, graph, zone), |
754 cache_(new (zone) MergeCache(zone)) {} | 723 cache_(new (zone) MergeCache(zone)), |
| 724 aliases_(zone), |
| 725 next_free_alias_(0) {} |
755 | 726 |
756 | 727 |
757 EscapeAnalysis::~EscapeAnalysis() {} | 728 EscapeAnalysis::~EscapeAnalysis() {} |
758 | 729 |
759 | 730 |
760 void EscapeAnalysis::Run() { | 731 void EscapeAnalysis::Run() { |
761 replacements_.resize(graph()->NodeCount()); | 732 replacements_.resize(graph()->NodeCount()); |
| 733 AssignAliases(); |
762 RunObjectAnalysis(); | 734 RunObjectAnalysis(); |
763 escape_status_.Run(); | 735 escape_status_.Run(); |
764 } | 736 } |
765 | 737 |
766 | 738 |
| 739 void EscapeAnalysis::AssignAliases() { |
| 740 ZoneVector<Node*> stack(zone()); |
| 741 stack.push_back(graph()->end()); |
| 742 CHECK_LT(graph()->NodeCount(), kUntrackable); |
| 743 aliases_.resize(graph()->NodeCount(), kNotReachable); |
| 744 aliases_[graph()->end()->id()] = kUntrackable; |
| 745 while (!stack.empty()) { |
| 746 Node* node = stack.back(); |
| 747 stack.pop_back(); |
| 748 switch (node->opcode()) { |
| 749 case IrOpcode::kAllocate: |
| 750 if (aliases_[node->id()] >= kUntrackable) { |
| 751 aliases_[node->id()] = NextAlias(); |
| 752 } |
| 753 break; |
| 754 case IrOpcode::kFinishRegion: { |
| 755 Node* allocate = NodeProperties::GetValueInput(node, 0); |
| 756 if (allocate->opcode() == IrOpcode::kAllocate) { |
| 757 if (aliases_[allocate->id()] >= kUntrackable) { |
| 758 if (aliases_[allocate->id()] == kNotReachable) { |
| 759 stack.push_back(allocate); |
| 760 } |
| 761 aliases_[allocate->id()] = NextAlias(); |
| 762 } |
| 763 aliases_[node->id()] = aliases_[allocate->id()]; |
| 764 } else { |
| 765 aliases_[node->id()] = NextAlias(); |
| 766 } |
| 767 break; |
| 768 } |
| 769 default: |
| 770 DCHECK_EQ(aliases_[node->id()], kUntrackable); |
| 771 break; |
| 772 } |
| 773 for (Edge edge : node->input_edges()) { |
| 774 Node* input = edge.to(); |
| 775 if (aliases_[input->id()] == kNotReachable) { |
| 776 stack.push_back(input); |
| 777 aliases_[input->id()] = kUntrackable; |
| 778 } |
| 779 } |
| 780 } |
| 781 |
| 782 if (FLAG_trace_turbo_escape) { |
| 783 PrintF("Discovered trackable nodes"); |
| 784 for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) { |
| 785 if (aliases_[id] < kUntrackable) { |
| 786 if (FLAG_trace_turbo_escape) { |
| 787 PrintF(" #%u", id); |
| 788 } |
| 789 } |
| 790 } |
| 791 PrintF("\n"); |
| 792 } |
| 793 } |
| 794 |
| 795 |
767 void EscapeAnalysis::RunObjectAnalysis() { | 796 void EscapeAnalysis::RunObjectAnalysis() { |
768 virtual_states_.resize(graph()->NodeCount()); | 797 virtual_states_.resize(graph()->NodeCount()); |
769 ZoneVector<Node*> stack(zone()); | 798 ZoneVector<Node*> stack(zone()); |
770 stack.push_back(graph()->start()); | 799 stack.push_back(graph()->start()); |
771 while (!stack.empty()) { | 800 while (!stack.empty()) { |
772 Node* node = stack.back(); | 801 Node* node = stack.back(); |
773 stack.pop_back(); | 802 stack.pop_back(); |
774 if (Process(node)) { | 803 if (aliases_[node->id()] != kNotReachable && Process(node)) { |
775 for (Edge edge : node->use_edges()) { | 804 for (Edge edge : node->use_edges()) { |
776 if (NodeProperties::IsEffectEdge(edge)) { | 805 if (NodeProperties::IsEffectEdge(edge)) { |
777 Node* use = edge.from(); | 806 Node* use = edge.from(); |
778 if ((use->opcode() != IrOpcode::kLoadField && | 807 if ((use->opcode() != IrOpcode::kLoadField && |
779 use->opcode() != IrOpcode::kLoadElement) || | 808 use->opcode() != IrOpcode::kLoadElement) || |
780 !IsDanglingEffectNode(use)) { | 809 !IsDanglingEffectNode(use)) { |
781 stack.push_back(use); | 810 stack.push_back(use); |
782 } | 811 } |
783 } | 812 } |
784 } | 813 } |
785 // First process loads: dangling loads are a problem otherwise. | 814 // First process loads: dangling loads are a problem otherwise. |
786 for (Edge edge : node->use_edges()) { | 815 for (Edge edge : node->use_edges()) { |
787 if (NodeProperties::IsEffectEdge(edge)) { | 816 if (NodeProperties::IsEffectEdge(edge)) { |
788 Node* use = edge.from(); | 817 Node* use = edge.from(); |
789 if ((use->opcode() == IrOpcode::kLoadField || | 818 if ((use->opcode() == IrOpcode::kLoadField || |
790 use->opcode() == IrOpcode::kLoadElement) && | 819 use->opcode() == IrOpcode::kLoadElement) && |
791 | |
792 | |
793 IsDanglingEffectNode(use)) { | 820 IsDanglingEffectNode(use)) { |
794 stack.push_back(use); | 821 stack.push_back(use); |
795 } | 822 } |
796 } | 823 } |
797 } | 824 } |
798 } | 825 } |
799 } | 826 } |
800 if (FLAG_trace_turbo_escape) { | 827 if (FLAG_trace_turbo_escape) { |
801 DebugPrint(); | 828 DebugPrint(); |
802 } | 829 } |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
912 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { | 939 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
913 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 940 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
914 node->op()->mnemonic()); | 941 node->op()->mnemonic()); |
915 UNREACHABLE(); | 942 UNREACHABLE(); |
916 } | 943 } |
917 Node* effect = NodeProperties::GetEffectInput(node); | 944 Node* effect = NodeProperties::GetEffectInput(node); |
918 // Break the cycle for effect phis. | 945 // Break the cycle for effect phis. |
919 if (effect->opcode() == IrOpcode::kEffectPhi) { | 946 if (effect->opcode() == IrOpcode::kEffectPhi) { |
920 if (virtual_states_[effect->id()] == nullptr) { | 947 if (virtual_states_[effect->id()] == nullptr) { |
921 virtual_states_[effect->id()] = | 948 virtual_states_[effect->id()] = |
922 new (zone()) VirtualState(zone(), graph()->NodeCount()); | 949 new (zone()) VirtualState(zone(), AliasCount()); |
923 } | 950 } |
924 } | 951 } |
925 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 952 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
926 if (IsEffectBranchPoint(effect)) { | 953 if (IsEffectBranchPoint(effect)) { |
927 if (FLAG_trace_turbo_escape) { | 954 if (FLAG_trace_turbo_escape) { |
928 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | 955 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", |
929 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 956 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
930 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 957 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
931 } | 958 } |
932 if (!virtual_states_[node->id()]) { | 959 if (!virtual_states_[node->id()]) { |
933 virtual_states_[node->id()] = | 960 virtual_states_[node->id()] = |
934 new (zone()) VirtualState(*virtual_states_[effect->id()]); | 961 new (zone()) VirtualState(*virtual_states_[effect->id()]); |
935 } else { | 962 } else { |
936 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 963 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
937 zone()); | 964 zone()); |
938 } | 965 } |
939 } else { | 966 } else { |
940 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 967 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
941 if (FLAG_trace_turbo_escape) { | 968 if (FLAG_trace_turbo_escape) { |
942 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | 969 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", |
943 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 970 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
944 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 971 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
945 } | 972 } |
946 } | 973 } |
947 } | 974 } |
948 | 975 |
949 | 976 |
950 void EscapeAnalysis::ProcessStart(Node* node) { | 977 void EscapeAnalysis::ProcessStart(Node* node) { |
951 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 978 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
952 virtual_states_[node->id()] = | 979 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); |
953 new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
954 } | 980 } |
955 | 981 |
956 | 982 |
957 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 983 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
958 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 984 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
959 bool changed = false; | 985 bool changed = false; |
960 | 986 |
961 VirtualState* mergeState = virtual_states_[node->id()]; | 987 VirtualState* mergeState = virtual_states_[node->id()]; |
962 if (!mergeState) { | 988 if (!mergeState) { |
963 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); | 989 mergeState = new (zone()) VirtualState(zone(), AliasCount()); |
964 virtual_states_[node->id()] = mergeState; | 990 virtual_states_[node->id()] = mergeState; |
965 changed = true; | 991 changed = true; |
966 if (FLAG_trace_turbo_escape) { | 992 if (FLAG_trace_turbo_escape) { |
967 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), | 993 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), |
968 static_cast<void*>(mergeState)); | 994 static_cast<void*>(mergeState)); |
969 } | 995 } |
970 } else if (mergeState->GetLastChanged() != node) { | 996 } else if (mergeState->GetLastChanged() != node) { |
971 changed = true; | 997 changed = true; |
972 } | 998 } |
973 | 999 |
974 cache_->Clear(); | 1000 cache_->Clear(); |
975 | 1001 |
976 if (FLAG_trace_turbo_escape) { | 1002 if (FLAG_trace_turbo_escape) { |
977 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), | 1003 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), |
978 static_cast<void*>(mergeState)); | 1004 static_cast<void*>(mergeState)); |
979 } | 1005 } |
980 | 1006 |
981 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1007 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
982 Node* input = NodeProperties::GetEffectInput(node, i); | 1008 Node* input = NodeProperties::GetEffectInput(node, i); |
983 VirtualState* state = virtual_states_[input->id()]; | 1009 VirtualState* state = virtual_states_[input->id()]; |
984 if (state) { | 1010 if (state) { |
985 cache_->push_back(state); | 1011 cache_->states().push_back(state); |
986 } | 1012 } |
987 if (FLAG_trace_turbo_escape) { | 1013 if (FLAG_trace_turbo_escape) { |
988 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1014 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
989 input->op()->mnemonic()); | 1015 input->op()->mnemonic()); |
990 } | 1016 } |
991 } | 1017 } |
992 if (FLAG_trace_turbo_escape) { | 1018 if (FLAG_trace_turbo_escape) { |
993 PrintF("\n"); | 1019 PrintF("\n"); |
994 } | 1020 } |
995 | 1021 |
(...skipping 15 matching lines...) Expand all Loading... |
1011 } | 1037 } |
1012 return changed; | 1038 return changed; |
1013 } | 1039 } |
1014 | 1040 |
1015 | 1041 |
1016 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1042 void EscapeAnalysis::ProcessAllocation(Node* node) { |
1017 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1043 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
1018 ForwardVirtualState(node); | 1044 ForwardVirtualState(node); |
1019 | 1045 |
1020 // Check if we have already processed this node. | 1046 // Check if we have already processed this node. |
1021 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; | 1047 if (virtual_states_[node->id()]->VirtualObjectFromAlias( |
| 1048 aliases_[node->id()])) { |
| 1049 return; |
| 1050 } |
1022 | 1051 |
1023 NumberMatcher size(node->InputAt(0)); | 1052 NumberMatcher size(node->InputAt(0)); |
1024 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1053 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
1025 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1054 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
1026 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1055 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
1027 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1056 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
1028 if (size.HasValue()) { | 1057 if (size.HasValue()) { |
1029 virtual_states_[node->id()]->SetVirtualObject( | 1058 virtual_states_[node->id()]->SetVirtualObject( |
1030 node->id(), new (zone()) VirtualObject(node->id(), zone(), | 1059 aliases_[node->id()], |
1031 size.Value() / kPointerSize)); | 1060 new (zone()) |
| 1061 VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); |
1032 } else { | 1062 } else { |
1033 virtual_states_[node->id()]->SetVirtualObject( | 1063 virtual_states_[node->id()]->SetVirtualObject( |
1034 node->id(), new (zone()) VirtualObject(node->id(), zone())); | 1064 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); |
1035 } | 1065 } |
1036 virtual_states_[node->id()]->LastChangedAt(node); | 1066 virtual_states_[node->id()]->LastChangedAt(node); |
1037 } | 1067 } |
1038 | 1068 |
1039 | 1069 |
1040 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1070 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
1041 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1071 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
1042 ForwardVirtualState(node); | 1072 ForwardVirtualState(node); |
1043 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1073 Node* allocation = NodeProperties::GetValueInput(node, 0); |
1044 if (allocation->opcode() == IrOpcode::kAllocate) { | 1074 if (allocation->opcode() == IrOpcode::kAllocate) { |
1045 VirtualState* states = virtual_states_[node->id()]; | 1075 VirtualState* state = virtual_states_[node->id()]; |
1046 DCHECK_NOT_NULL(states->GetVirtualObject(allocation)); | 1076 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { |
1047 if (!states->GetVirtualObject(node->id())) { | 1077 VirtualObject* vobj_alloc = |
1048 states->SetVirtualObject(node->id(), | 1078 state->VirtualObjectFromAlias(aliases_[allocation->id()]); |
1049 states->GetVirtualObject(allocation)); | 1079 DCHECK_NOT_NULL(vobj_alloc); |
| 1080 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); |
1050 if (FLAG_trace_turbo_escape) { | 1081 if (FLAG_trace_turbo_escape) { |
1051 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | 1082 PrintF("Linked finish region node #%d to node #%d\n", node->id(), |
1052 allocation->id()); | 1083 allocation->id()); |
1053 } | 1084 } |
1054 states->LastChangedAt(node); | 1085 state->LastChangedAt(node); |
1055 } | 1086 } |
1056 } | 1087 } |
1057 } | 1088 } |
1058 | 1089 |
1059 | 1090 |
1060 Node* EscapeAnalysis::replacement(NodeId id) { | 1091 Node* EscapeAnalysis::replacement(NodeId id) { |
1061 if (id >= replacements_.size()) return nullptr; | 1092 if (id >= replacements_.size()) return nullptr; |
1062 return replacements_[id]; | 1093 return replacements_[id]; |
1063 } | 1094 } |
1064 | 1095 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1132 } | 1163 } |
1133 | 1164 |
1134 | 1165 |
1135 bool EscapeAnalysis::SetEscaped(Node* node) { | 1166 bool EscapeAnalysis::SetEscaped(Node* node) { |
1136 return escape_status_.SetEscaped(node); | 1167 return escape_status_.SetEscaped(node); |
1137 } | 1168 } |
1138 | 1169 |
1139 | 1170 |
1140 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1171 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
1141 if (VirtualState* states = virtual_states_[at->id()]) { | 1172 if (VirtualState* states = virtual_states_[at->id()]) { |
1142 return states->GetVirtualObject(id); | 1173 return states->VirtualObjectFromAlias(aliases_[id]); |
1143 } | 1174 } |
1144 return nullptr; | 1175 return nullptr; |
1145 } | 1176 } |
1146 | 1177 |
1147 | 1178 |
1148 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1179 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
1149 Node* node) { | 1180 Node* node) { |
1150 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); | 1181 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); |
1151 while (obj && replacement(obj->id()) && | 1182 while (obj && replacement(obj->id())) { |
1152 state->GetVirtualObject(replacement(obj->id()))) { | 1183 if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) { |
1153 obj = state->GetVirtualObject(replacement(obj->id())); | 1184 obj = next; |
| 1185 } else { |
| 1186 break; |
| 1187 } |
1154 } | 1188 } |
1155 return obj; | 1189 return obj; |
1156 } | 1190 } |
1157 | 1191 |
1158 | 1192 |
1159 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1193 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
1160 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1194 DCHECK(IsVirtual(left) && IsVirtual(right)); |
1161 left = ResolveReplacement(left); | 1195 left = ResolveReplacement(left); |
1162 right = ResolveReplacement(right); | 1196 right = ResolveReplacement(right); |
1163 if (IsEquivalentPhi(left, right)) { | 1197 if (IsEquivalentPhi(left, right)) { |
(...skipping 14 matching lines...) Expand all Loading... |
1178 if (FLAG_trace_turbo_escape) { | 1212 if (FLAG_trace_turbo_escape) { |
1179 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 1213 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
1180 } | 1214 } |
1181 | 1215 |
1182 cache_->fields().clear(); | 1216 cache_->fields().clear(); |
1183 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1217 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
1184 Node* input = NodeProperties::GetValueInput(node, i); | 1218 Node* input = NodeProperties::GetValueInput(node, i); |
1185 cache_->fields().push_back(input); | 1219 cache_->fields().push_back(input); |
1186 } | 1220 } |
1187 | 1221 |
1188 cache_->LoadVirtualObjectsForFieldsFrom(state); | 1222 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); |
1189 if (cache_->objects().size() == cache_->fields().size()) { | 1223 if (cache_->objects().size() == cache_->fields().size()) { |
1190 cache_->GetFields(offset); | 1224 cache_->GetFields(offset); |
1191 if (cache_->fields().size() == cache_->objects().size()) { | 1225 if (cache_->fields().size() == cache_->objects().size()) { |
1192 Node* rep = replacement(node); | 1226 Node* rep = replacement(node); |
1193 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1227 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
1194 int value_input_count = static_cast<int>(cache_->fields().size()); | 1228 int value_input_count = static_cast<int>(cache_->fields().size()); |
1195 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1229 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
1196 Node* phi = graph()->NewNode( | 1230 Node* phi = graph()->NewNode( |
1197 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1231 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
1198 value_input_count + 1, &cache_->fields().front()); | 1232 value_input_count + 1, &cache_->fields().front()); |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1380 } | 1414 } |
1381 } | 1415 } |
1382 return new_object_state; | 1416 return new_object_state; |
1383 } | 1417 } |
1384 } | 1418 } |
1385 } | 1419 } |
1386 return nullptr; | 1420 return nullptr; |
1387 } | 1421 } |
1388 | 1422 |
1389 | 1423 |
1390 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { | 1424 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) { |
1391 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); | 1425 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(), |
| 1426 object->field_count()); |
1392 for (size_t i = 0; i < object->field_count(); ++i) { | 1427 for (size_t i = 0; i < object->field_count(); ++i) { |
1393 if (Node* f = object->GetField(i)) { | 1428 if (Node* f = object->GetField(i)) { |
1394 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1429 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
1395 } | 1430 } |
1396 } | 1431 } |
1397 } | 1432 } |
1398 | 1433 |
1399 | 1434 |
1400 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1435 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
1401 PrintF("Dumping object state %p\n", static_cast<void*>(state)); | 1436 PrintF("Dumping object state %p\n", static_cast<void*>(state)); |
1402 for (size_t id = 0; id < state->size(); id++) { | 1437 for (Alias alias = 0; alias < AliasCount(); ++alias) { |
1403 if (VirtualObject* object = state->GetVirtualObject(id)) { | 1438 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { |
1404 if (object->id() == id) { | 1439 DebugPrintObject(object, alias); |
1405 DebugPrintObject(object, static_cast<int>(id)); | |
1406 } else { | |
1407 PrintF(" Object #%zu links to object #%d\n", id, object->id()); | |
1408 } | |
1409 } | 1440 } |
1410 } | 1441 } |
1411 } | 1442 } |
1412 | 1443 |
1413 | 1444 |
1414 void EscapeAnalysis::DebugPrint() { | 1445 void EscapeAnalysis::DebugPrint() { |
1415 ZoneVector<VirtualState*> object_states(zone()); | 1446 ZoneVector<VirtualState*> object_states(zone()); |
1416 for (NodeId id = 0; id < virtual_states_.size(); id++) { | 1447 for (NodeId id = 0; id < virtual_states_.size(); id++) { |
1417 if (VirtualState* states = virtual_states_[id]) { | 1448 if (VirtualState* states = virtual_states_[id]) { |
1418 if (std::find(object_states.begin(), object_states.end(), states) == | 1449 if (std::find(object_states.begin(), object_states.end(), states) == |
1419 object_states.end()) { | 1450 object_states.end()) { |
1420 object_states.push_back(states); | 1451 object_states.push_back(states); |
1421 } | 1452 } |
1422 } | 1453 } |
1423 } | 1454 } |
1424 for (size_t n = 0; n < object_states.size(); n++) { | 1455 for (size_t n = 0; n < object_states.size(); n++) { |
1425 DebugPrintState(object_states[n]); | 1456 DebugPrintState(object_states[n]); |
1426 } | 1457 } |
1427 } | 1458 } |
1428 | 1459 |
| 1460 |
| 1461 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
| 1462 Node* node) { |
| 1463 if (node->id() >= aliases_.size()) return nullptr; |
| 1464 Alias alias = aliases_[node->id()]; |
| 1465 if (alias >= state->size()) return nullptr; |
| 1466 return state->VirtualObjectFromAlias(alias); |
| 1467 } |
| 1468 |
1429 } // namespace compiler | 1469 } // namespace compiler |
1430 } // namespace internal | 1470 } // namespace internal |
1431 } // namespace v8 | 1471 } // namespace v8 |
OLD | NEW |