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 "src/base/flags.h" | 7 #include "src/base/flags.h" |
8 #include "src/bootstrapper.h" | 8 #include "src/bootstrapper.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/common-operator.h" | 10 #include "src/compiler/common-operator.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 } | 56 } |
57 bool IsVirtual() const { return status_ == kTracked; } | 57 bool IsVirtual() const { return status_ == kTracked; } |
58 bool IsTracked() const { return status_ != kUntracked; } | 58 bool IsTracked() const { return status_ != kUntracked; } |
59 Node* GetReplacement() { return replacement_; } | 59 Node* GetReplacement() { return replacement_; } |
60 bool SetReplacement(Node* node) { | 60 bool SetReplacement(Node* node) { |
61 bool changed = replacement_ != node; | 61 bool changed = replacement_ != node; |
62 replacement_ = node; | 62 replacement_ = node; |
63 return changed; | 63 return changed; |
64 } | 64 } |
65 | 65 |
66 size_t fields() { return fields_.size(); } | 66 Node** fields_array() { return &fields_.front(); } |
67 bool ResizeFields(size_t field_number) { | 67 size_t field_count() { return fields_.size(); } |
68 if (field_number != fields_.size()) { | 68 bool ResizeFields(size_t field_count) { |
69 fields_.resize(field_number); | 69 if (field_count != fields_.size()) { |
| 70 fields_.resize(field_count); |
70 return true; | 71 return true; |
71 } | 72 } |
72 return false; | 73 return false; |
73 } | 74 } |
74 | 75 bool ClearAllFields() { |
| 76 bool changed = false; |
| 77 for (size_t i = 0; i < fields_.size(); ++i) { |
| 78 if (fields_[i] != nullptr) { |
| 79 fields_[i] = nullptr; |
| 80 changed = true; |
| 81 } |
| 82 } |
| 83 return changed; |
| 84 } |
75 bool UpdateFrom(const VirtualObject& other); | 85 bool UpdateFrom(const VirtualObject& other); |
76 | 86 |
77 NodeId id() { return id_; } | 87 NodeId id() { return id_; } |
78 void id(NodeId id) { id_ = id; } | 88 void id(NodeId id) { id_ = id; } |
79 | 89 |
80 private: | 90 private: |
81 NodeId id_; | 91 NodeId id_; |
82 Status status_; | 92 Status status_; |
83 ZoneVector<Node*> fields_; | 93 ZoneVector<Node*> fields_; |
84 Node* replacement_; | 94 Node* replacement_; |
(...skipping 20 matching lines...) Expand all Loading... |
105 | 115 |
106 | 116 |
107 // ------------------------------VirtualState----------------------------------- | 117 // ------------------------------VirtualState----------------------------------- |
108 | 118 |
109 | 119 |
110 class VirtualState : public ZoneObject { | 120 class VirtualState : public ZoneObject { |
111 public: | 121 public: |
112 VirtualState(Zone* zone, size_t size); | 122 VirtualState(Zone* zone, size_t size); |
113 VirtualState(const VirtualState& states); | 123 VirtualState(const VirtualState& states); |
114 | 124 |
| 125 VirtualObject* ResolveVirtualObject(Node* node); |
115 VirtualObject* GetVirtualObject(Node* node); | 126 VirtualObject* GetVirtualObject(Node* node); |
116 VirtualObject* GetVirtualObject(size_t id); | 127 VirtualObject* GetVirtualObject(size_t id); |
117 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); | 128 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); |
118 void SetVirtualObject(NodeId id, VirtualObject* state); | 129 void SetVirtualObject(NodeId id, VirtualObject* state); |
119 void LastChangedAt(Node* node) { last_changed_ = node; } | 130 void LastChangedAt(Node* node) { last_changed_ = node; } |
120 Node* GetLastChanged() { return last_changed_; } | 131 Node* GetLastChanged() { return last_changed_; } |
121 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); | 132 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); |
122 Node* ResolveReplacement(Node* node); | 133 Node* ResolveReplacement(Node* node); |
123 bool UpdateReplacement(Node* node, Node* rep, Zone* zone); | 134 bool UpdateReplacement(Node* node, Node* rep, Zone* zone); |
124 bool UpdateFrom(VirtualState* state, Zone* zone); | 135 bool UpdateFrom(VirtualState* state, Zone* zone); |
(...skipping 25 matching lines...) Expand all Loading... |
150 } | 161 } |
151 } | 162 } |
152 for (size_t i = 0; i < state.info_.size(); ++i) { | 163 for (size_t i = 0; i < state.info_.size(); ++i) { |
153 if (state.info_[i] && state.info_[i]->id() != i) { | 164 if (state.info_[i] && state.info_[i]->id() != i) { |
154 info_[i] = info_[state.info_[i]->id()]; | 165 info_[i] = info_[state.info_[i]->id()]; |
155 } | 166 } |
156 } | 167 } |
157 } | 168 } |
158 | 169 |
159 | 170 |
160 VirtualObject* VirtualState::GetVirtualObject(size_t id) { return info_[id]; } | 171 VirtualObject* VirtualState::GetVirtualObject(size_t id) { |
| 172 if (id >= info_.size()) return nullptr; |
| 173 return info_[id]; |
| 174 } |
161 | 175 |
162 | 176 |
163 VirtualObject* VirtualState::GetVirtualObject(Node* node) { | 177 VirtualObject* VirtualState::GetVirtualObject(Node* node) { |
164 return GetVirtualObject(node->id()); | 178 return GetVirtualObject(node->id()); |
165 } | 179 } |
166 | 180 |
167 | 181 |
| 182 VirtualObject* VirtualState::ResolveVirtualObject(Node* node) { |
| 183 VirtualObject* obj = GetVirtualObject(node->id()); |
| 184 while (obj && !obj->IsTracked() && obj->GetReplacement() && |
| 185 GetVirtualObject(obj->GetReplacement())) { |
| 186 obj = GetVirtualObject(obj->GetReplacement()); |
| 187 } |
| 188 return obj; |
| 189 } |
| 190 |
| 191 |
168 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, | 192 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id, |
169 Zone* zone) { | 193 Zone* zone) { |
170 if (VirtualObject* obj = GetVirtualObject(id)) { | 194 if (VirtualObject* obj = GetVirtualObject(id)) { |
171 return obj; | 195 return obj; |
172 } | 196 } |
173 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); | 197 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); |
174 SetVirtualObject(id, obj); | 198 SetVirtualObject(id, obj); |
175 return obj; | 199 return obj; |
176 } | 200 } |
177 | 201 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 bool changed = false; | 263 bool changed = false; |
240 for (NodeId id = 0; id < std::min(left->size(), right->size()); ++id) { | 264 for (NodeId id = 0; id < std::min(left->size(), right->size()); ++id) { |
241 VirtualObject* ls = left->GetVirtualObject(id); | 265 VirtualObject* ls = left->GetVirtualObject(id); |
242 VirtualObject* rs = right->GetVirtualObject(id); | 266 VirtualObject* rs = right->GetVirtualObject(id); |
243 | 267 |
244 if (ls != nullptr && rs != nullptr) { | 268 if (ls != nullptr && rs != nullptr) { |
245 if (FLAG_trace_turbo_escape) { | 269 if (FLAG_trace_turbo_escape) { |
246 PrintF(" Merging fields of #%d\n", id); | 270 PrintF(" Merging fields of #%d\n", id); |
247 } | 271 } |
248 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); | 272 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); |
249 size_t fields = std::max(ls->fields(), rs->fields()); | 273 size_t fields = std::max(ls->field_count(), rs->field_count()); |
250 changed = mergeObject->ResizeFields(fields) || changed; | 274 changed = mergeObject->ResizeFields(fields) || changed; |
251 for (size_t i = 0; i < fields; ++i) { | 275 for (size_t i = 0; i < fields; ++i) { |
252 if (ls->GetField(i) == rs->GetField(i)) { | 276 if (ls->GetField(i) == rs->GetField(i)) { |
253 changed = mergeObject->SetField(i, ls->GetField(i)) || changed; | 277 changed = mergeObject->SetField(i, ls->GetField(i)) || changed; |
254 if (FLAG_trace_turbo_escape && ls->GetField(i)) { | 278 if (FLAG_trace_turbo_escape && ls->GetField(i)) { |
255 PrintF(" Field %zu agree on rep #%d\n", i, | 279 PrintF(" Field %zu agree on rep #%d\n", i, |
256 ls->GetField(i)->id()); | 280 ls->GetField(i)->id()); |
257 } | 281 } |
258 } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) { | 282 } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) { |
259 Node* phi = graph->NewNode(common->Phi(kMachAnyTagged, 2), | 283 Node* rep = mergeObject->GetField(i); |
260 ls->GetField(i), rs->GetField(i), control); | 284 if (!rep || rep->opcode() != IrOpcode::kPhi || |
261 if (mergeObject->SetField(i, phi)) { | 285 NodeProperties::GetValueInput(rep, 0) != ls->GetField(i) || |
| 286 NodeProperties::GetValueInput(rep, 1) != rs->GetField(i)) { |
| 287 Node* phi = |
| 288 graph->NewNode(common->Phi(kMachAnyTagged, 2), ls->GetField(i), |
| 289 rs->GetField(i), control); |
| 290 if (mergeObject->SetField(i, phi)) { |
| 291 if (FLAG_trace_turbo_escape) { |
| 292 PrintF(" Creating Phi #%d as merge of #%d and #%d\n", |
| 293 phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id()); |
| 294 } |
| 295 changed = true; |
| 296 } |
| 297 } else { |
262 if (FLAG_trace_turbo_escape) { | 298 if (FLAG_trace_turbo_escape) { |
263 PrintF(" Creating Phi #%d as merge of #%d and #%d\n", | 299 PrintF(" Retaining Phi #%d as merge of #%d and #%d\n", |
264 phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id()); | 300 rep->id(), ls->GetField(i)->id(), rs->GetField(i)->id()); |
265 } | 301 } |
266 changed = true; | |
267 } | 302 } |
268 } else { | 303 } else { |
269 changed = mergeObject->SetField(i, nullptr) || changed; | 304 changed = mergeObject->SetField(i, nullptr) || changed; |
270 } | 305 } |
271 } | 306 } |
| 307 } else if (ls) { |
| 308 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); |
| 309 changed = mergeObject->UpdateFrom(*ls) || changed; |
| 310 } else if (rs) { |
| 311 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); |
| 312 changed = mergeObject->UpdateFrom(*rs) || changed; |
272 } | 313 } |
273 } | 314 } |
274 return changed; | 315 return changed; |
275 } | 316 } |
276 | 317 |
277 | 318 |
278 Node* VirtualState::ResolveReplacement(Node* node) { | 319 Node* VirtualState::ResolveReplacement(Node* node) { |
279 if (VirtualObject* obj = GetVirtualObject(node)) { | 320 Node* replacement = node; |
280 if (Node* rep = obj->GetReplacement()) { | 321 VirtualObject* obj = GetVirtualObject(node); |
281 return rep; | 322 while (obj != nullptr && obj->GetReplacement()) { |
282 } | 323 replacement = obj->GetReplacement(); |
| 324 obj = GetVirtualObject(replacement); |
283 } | 325 } |
284 return node; | 326 return replacement; |
285 } | 327 } |
286 | 328 |
287 | 329 |
288 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) { | 330 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) { |
289 if (!GetVirtualObject(node)) { | 331 if (!GetVirtualObject(node)) { |
290 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone)); | 332 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone)); |
291 } | 333 } |
292 if (GetVirtualObject(node)->SetReplacement(rep)) { | 334 if (GetVirtualObject(node)->SetReplacement(rep)) { |
293 LastChangedAt(node); | 335 LastChangedAt(node); |
294 if (FLAG_trace_turbo_escape) { | 336 if (FLAG_trace_turbo_escape) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 switch (node->opcode()) { | 423 switch (node->opcode()) { |
382 case IrOpcode::kAllocate: | 424 case IrOpcode::kAllocate: |
383 ProcessAllocate(node); | 425 ProcessAllocate(node); |
384 break; | 426 break; |
385 case IrOpcode::kFinishRegion: | 427 case IrOpcode::kFinishRegion: |
386 ProcessFinishRegion(node); | 428 ProcessFinishRegion(node); |
387 break; | 429 break; |
388 case IrOpcode::kStoreField: | 430 case IrOpcode::kStoreField: |
389 ProcessStoreField(node); | 431 ProcessStoreField(node); |
390 break; | 432 break; |
391 case IrOpcode::kLoadField: { | 433 case IrOpcode::kStoreElement: |
| 434 ProcessStoreElement(node); |
| 435 break; |
| 436 case IrOpcode::kLoadField: |
| 437 case IrOpcode::kLoadElement: { |
392 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) { | 438 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) { |
393 if (rep->opcode() == IrOpcode::kAllocate || | 439 if (rep->opcode() == IrOpcode::kAllocate || |
394 rep->opcode() == IrOpcode::kFinishRegion) { | 440 rep->opcode() == IrOpcode::kFinishRegion) { |
395 if (CheckUsesForEscape(node, rep)) { | 441 if (CheckUsesForEscape(node, rep)) { |
396 RevisitInputs(rep); | 442 RevisitInputs(rep); |
397 RevisitUses(rep); | 443 RevisitUses(rep); |
398 } | 444 } |
399 } | 445 } |
400 } | 446 } |
401 break; | 447 break; |
(...skipping 16 matching lines...) Expand all Loading... |
418 if (IsEscaped(to) && SetEscaped(val)) { | 464 if (IsEscaped(to) && SetEscaped(val)) { |
419 RevisitUses(val); | 465 RevisitUses(val); |
420 if (FLAG_trace_turbo_escape) { | 466 if (FLAG_trace_turbo_escape) { |
421 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | 467 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", |
422 val->id(), val->op()->mnemonic(), to->id()); | 468 val->id(), val->op()->mnemonic(), to->id()); |
423 } | 469 } |
424 } | 470 } |
425 } | 471 } |
426 | 472 |
427 | 473 |
| 474 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { |
| 475 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 476 Node* to = NodeProperties::GetValueInput(node, 0); |
| 477 Node* val = NodeProperties::GetValueInput(node, 2); |
| 478 if (IsEscaped(to) && SetEscaped(val)) { |
| 479 RevisitUses(val); |
| 480 if (FLAG_trace_turbo_escape) { |
| 481 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", |
| 482 val->id(), val->op()->mnemonic(), to->id()); |
| 483 } |
| 484 } |
| 485 } |
| 486 |
| 487 |
428 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 488 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
429 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 489 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
430 if (!HasEntry(node)) { | 490 if (!HasEntry(node)) { |
431 info_[node->id()] = kVirtual; | 491 info_[node->id()] = kVirtual; |
432 if (FLAG_trace_turbo_escape) { | 492 if (FLAG_trace_turbo_escape) { |
433 PrintF("Created status entry for node #%d (%s)\n", node->id(), | 493 PrintF("Created status entry for node #%d (%s)\n", node->id(), |
434 node->op()->mnemonic()); | 494 node->op()->mnemonic()); |
435 } | 495 } |
436 NumberMatcher size(node->InputAt(0)); | 496 NumberMatcher size(node->InputAt(0)); |
437 if (!size.HasValue() && SetEscaped(node)) { | 497 if (!size.HasValue() && SetEscaped(node)) { |
438 RevisitUses(node); | 498 RevisitUses(node); |
439 if (FLAG_trace_turbo_escape) { | 499 if (FLAG_trace_turbo_escape) { |
440 PrintF("Setting #%d to escaped because of non-const alloc\n", | 500 PrintF("Setting #%d to escaped because of non-const alloc\n", |
441 node->id()); | 501 node->id()); |
442 } | 502 } |
443 // This node is known to escape, uses do not have to be checked. | 503 // This node is known to escape, uses do not have to be checked. |
444 return; | 504 return; |
445 } | 505 } |
446 } | 506 } |
447 if (CheckUsesForEscape(node)) { | 507 if (CheckUsesForEscape(node, true)) { |
448 RevisitUses(node); | 508 RevisitUses(node); |
449 } | 509 } |
450 } | 510 } |
451 | 511 |
452 | 512 |
453 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep) { | 513 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
| 514 bool phi_escaping) { |
454 for (Edge edge : uses->use_edges()) { | 515 for (Edge edge : uses->use_edges()) { |
455 Node* use = edge.from(); | 516 Node* use = edge.from(); |
456 if (!NodeProperties::IsValueEdge(edge)) continue; | 517 if (!NodeProperties::IsValueEdge(edge) && |
| 518 !NodeProperties::IsContextEdge(edge)) |
| 519 continue; |
457 switch (use->opcode()) { | 520 switch (use->opcode()) { |
458 case IrOpcode::kStoreField: | 521 case IrOpcode::kStoreField: |
459 case IrOpcode::kLoadField: | 522 case IrOpcode::kLoadField: |
| 523 case IrOpcode::kStoreElement: |
| 524 case IrOpcode::kLoadElement: |
460 case IrOpcode::kFrameState: | 525 case IrOpcode::kFrameState: |
461 case IrOpcode::kStateValues: | 526 case IrOpcode::kStateValues: |
462 case IrOpcode::kReferenceEqual: | 527 case IrOpcode::kReferenceEqual: |
463 case IrOpcode::kFinishRegion: | 528 case IrOpcode::kFinishRegion: |
464 case IrOpcode::kPhi: | 529 case IrOpcode::kPhi: |
465 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) { | 530 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) { |
466 if (FLAG_trace_turbo_escape) { | 531 if (FLAG_trace_turbo_escape) { |
467 PrintF( | 532 PrintF( |
468 "Setting #%d (%s) to escaped because of use by escaping node " | 533 "Setting #%d (%s) to escaped because of use by escaping node " |
469 "#%d (%s)\n", | 534 "#%d (%s)\n", |
470 rep->id(), rep->op()->mnemonic(), use->id(), | 535 rep->id(), rep->op()->mnemonic(), use->id(), |
471 use->op()->mnemonic()); | 536 use->op()->mnemonic()); |
472 } | 537 } |
473 return true; | 538 return true; |
474 } | 539 } |
| 540 if (phi_escaping && use->opcode() == IrOpcode::kPhi && |
| 541 SetEscaped(rep)) { |
| 542 if (FLAG_trace_turbo_escape) { |
| 543 PrintF( |
| 544 "Setting #%d (%s) to escaped because of use by phi node " |
| 545 "#%d (%s)\n", |
| 546 rep->id(), rep->op()->mnemonic(), use->id(), |
| 547 use->op()->mnemonic()); |
| 548 } |
| 549 return true; |
| 550 } |
475 break; | 551 break; |
476 default: | 552 default: |
477 if (SetEscaped(rep)) { | 553 if (SetEscaped(rep)) { |
478 if (FLAG_trace_turbo_escape) { | 554 if (FLAG_trace_turbo_escape) { |
479 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 555 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
480 rep->id(), rep->op()->mnemonic(), use->id(), | 556 rep->id(), rep->op()->mnemonic(), use->id(), |
481 use->op()->mnemonic()); | 557 use->op()->mnemonic()); |
482 } | 558 } |
483 return true; | 559 return true; |
484 } | 560 } |
(...skipping 11 matching lines...) Expand all Loading... |
496 return false; | 572 return false; |
497 } | 573 } |
498 | 574 |
499 | 575 |
500 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | 576 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { |
501 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 577 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
502 if (!HasEntry(node)) { | 578 if (!HasEntry(node)) { |
503 info_[node->id()] = kVirtual; | 579 info_[node->id()] = kVirtual; |
504 RevisitUses(node); | 580 RevisitUses(node); |
505 } | 581 } |
506 if (CheckUsesForEscape(node)) { | 582 if (CheckUsesForEscape(node, true)) { |
507 RevisitInputs(node); | 583 RevisitInputs(node); |
508 } | 584 } |
509 } | 585 } |
510 | 586 |
511 | 587 |
512 void EscapeStatusAnalysis::DebugPrint() { | 588 void EscapeStatusAnalysis::DebugPrint() { |
513 for (NodeId id = 0; id < info_.size(); id++) { | 589 for (NodeId id = 0; id < info_.size(); id++) { |
514 if (info_[id] != kUnknown) { | 590 if (info_[id] != kUnknown) { |
515 PrintF("Node #%d is %s\n", id, | 591 PrintF("Node #%d is %s\n", id, |
516 info_[id] == kEscaped ? "escaping" : "virtual"); | 592 info_[id] == kEscaped ? "escaping" : "virtual"); |
(...skipping 18 matching lines...) Expand all Loading... |
535 | 611 |
536 | 612 |
537 void EscapeAnalysis::Run() { | 613 void EscapeAnalysis::Run() { |
538 RunObjectAnalysis(); | 614 RunObjectAnalysis(); |
539 escape_status_.Run(); | 615 escape_status_.Run(); |
540 } | 616 } |
541 | 617 |
542 | 618 |
543 void EscapeAnalysis::RunObjectAnalysis() { | 619 void EscapeAnalysis::RunObjectAnalysis() { |
544 virtual_states_.resize(graph()->NodeCount()); | 620 virtual_states_.resize(graph()->NodeCount()); |
545 ZoneVector<Node*> queue(zone()); | 621 ZoneVector<Node*> stack(zone()); |
546 queue.push_back(graph()->start()); | 622 stack.push_back(graph()->start()); |
547 while (!queue.empty()) { | 623 while (!stack.empty()) { |
548 Node* node = queue.back(); | 624 Node* node = stack.back(); |
549 queue.pop_back(); | 625 stack.pop_back(); |
550 if (Process(node)) { | 626 if (Process(node)) { |
551 for (Edge edge : node->use_edges()) { | 627 for (Edge edge : node->use_edges()) { |
552 if (NodeProperties::IsEffectEdge(edge)) { | 628 if (NodeProperties::IsEffectEdge(edge)) { |
553 Node* use = edge.from(); | 629 Node* use = edge.from(); |
554 if (use->opcode() != IrOpcode::kLoadField || | 630 if ((use->opcode() != IrOpcode::kLoadField && |
| 631 use->opcode() != IrOpcode::kLoadElement) || |
555 !IsDanglingEffectNode(use)) { | 632 !IsDanglingEffectNode(use)) { |
556 queue.push_back(use); | 633 stack.push_back(use); |
557 } | 634 } |
558 } | 635 } |
559 } | 636 } |
560 // First process loads: dangling loads are a problem otherwise. | 637 // First process loads: dangling loads are a problem otherwise. |
561 for (Edge edge : node->use_edges()) { | 638 for (Edge edge : node->use_edges()) { |
562 if (NodeProperties::IsEffectEdge(edge)) { | 639 if (NodeProperties::IsEffectEdge(edge)) { |
563 Node* use = edge.from(); | 640 Node* use = edge.from(); |
564 if (use->opcode() == IrOpcode::kLoadField && | 641 if ((use->opcode() == IrOpcode::kLoadField || |
| 642 use->opcode() == IrOpcode::kLoadElement) && |
| 643 |
| 644 |
565 IsDanglingEffectNode(use)) { | 645 IsDanglingEffectNode(use)) { |
566 queue.push_back(use); | 646 stack.push_back(use); |
567 } | 647 } |
568 } | 648 } |
569 } | 649 } |
570 } | 650 } |
571 } | 651 } |
572 if (FLAG_trace_turbo_escape) { | 652 if (FLAG_trace_turbo_escape) { |
573 DebugPrint(); | 653 DebugPrint(); |
574 } | 654 } |
575 } | 655 } |
576 | 656 |
(...skipping 20 matching lines...) Expand all Loading... |
597 break; | 677 break; |
598 case IrOpcode::kFinishRegion: | 678 case IrOpcode::kFinishRegion: |
599 ProcessFinishRegion(node); | 679 ProcessFinishRegion(node); |
600 break; | 680 break; |
601 case IrOpcode::kStoreField: | 681 case IrOpcode::kStoreField: |
602 ProcessStoreField(node); | 682 ProcessStoreField(node); |
603 break; | 683 break; |
604 case IrOpcode::kLoadField: | 684 case IrOpcode::kLoadField: |
605 ProcessLoadField(node); | 685 ProcessLoadField(node); |
606 break; | 686 break; |
| 687 case IrOpcode::kStoreElement: |
| 688 ProcessStoreElement(node); |
| 689 break; |
| 690 case IrOpcode::kLoadElement: |
| 691 ProcessLoadElement(node); |
| 692 break; |
607 case IrOpcode::kStart: | 693 case IrOpcode::kStart: |
608 ProcessStart(node); | 694 ProcessStart(node); |
609 break; | 695 break; |
610 case IrOpcode::kEffectPhi: | 696 case IrOpcode::kEffectPhi: |
611 return ProcessEffectPhi(node); | 697 return ProcessEffectPhi(node); |
612 break; | 698 break; |
613 default: | 699 default: |
614 if (node->op()->EffectInputCount() > 0) { | 700 if (node->op()->EffectInputCount() > 0) { |
615 ForwardVirtualState(node); | 701 ForwardVirtualState(node); |
616 } | 702 } |
| 703 ProcessAllocationUsers(node); |
617 break; | 704 break; |
618 } | 705 } |
619 return true; | 706 return true; |
620 } | 707 } |
621 | 708 |
622 | 709 |
| 710 void EscapeAnalysis::ProcessAllocationUsers(Node* node) { |
| 711 for (Edge edge : node->input_edges()) { |
| 712 Node* input = edge.to(); |
| 713 if (!NodeProperties::IsValueEdge(edge) && |
| 714 !NodeProperties::IsContextEdge(edge)) |
| 715 continue; |
| 716 switch (node->opcode()) { |
| 717 case IrOpcode::kStoreField: |
| 718 case IrOpcode::kLoadField: |
| 719 case IrOpcode::kStoreElement: |
| 720 case IrOpcode::kLoadElement: |
| 721 case IrOpcode::kFrameState: |
| 722 case IrOpcode::kStateValues: |
| 723 case IrOpcode::kReferenceEqual: |
| 724 case IrOpcode::kFinishRegion: |
| 725 case IrOpcode::kPhi: |
| 726 break; |
| 727 default: |
| 728 VirtualState* states = virtual_states_[node->id()]; |
| 729 if (VirtualObject* obj = states->ResolveVirtualObject(input)) { |
| 730 if (obj->ClearAllFields()) { |
| 731 states->LastChangedAt(node); |
| 732 } |
| 733 } |
| 734 break; |
| 735 } |
| 736 } |
| 737 } |
| 738 |
| 739 |
623 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { | 740 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { |
624 int count = 0; | 741 int count = 0; |
625 for (Edge edge : node->use_edges()) { | 742 for (Edge edge : node->use_edges()) { |
626 Node* use = edge.from(); | 743 Node* use = edge.from(); |
627 if (NodeProperties::IsEffectEdge(edge) && | 744 if (NodeProperties::IsEffectEdge(edge) && |
628 use->opcode() != IrOpcode::kLoadField) { | 745 use->opcode() != IrOpcode::kLoadField) { |
629 if (++count > 1) { | 746 if (++count > 1) { |
630 return true; | 747 return true; |
631 } | 748 } |
632 } | 749 } |
633 } | 750 } |
634 return false; | 751 return false; |
635 } | 752 } |
636 | 753 |
637 | 754 |
638 void EscapeAnalysis::ForwardVirtualState(Node* node) { | 755 void EscapeAnalysis::ForwardVirtualState(Node* node) { |
639 DCHECK_EQ(node->op()->EffectInputCount(), 1); | 756 DCHECK_EQ(node->op()->EffectInputCount(), 1); |
640 if (node->opcode() != IrOpcode::kLoadField && IsDanglingEffectNode(node)) { | 757 if (node->opcode() != IrOpcode::kLoadField && |
| 758 node->opcode() != IrOpcode::kLoadElement && |
| 759 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
641 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 760 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
642 node->op()->mnemonic()); | 761 node->op()->mnemonic()); |
643 DCHECK(false); | 762 UNREACHABLE(); |
644 } | 763 } |
645 Node* effect = NodeProperties::GetEffectInput(node); | 764 Node* effect = NodeProperties::GetEffectInput(node); |
646 // Break the cycle for effect phis. | 765 // Break the cycle for effect phis. |
647 if (effect->opcode() == IrOpcode::kEffectPhi) { | 766 if (effect->opcode() == IrOpcode::kEffectPhi) { |
648 if (virtual_states_[effect->id()] == nullptr) { | 767 if (virtual_states_[effect->id()] == nullptr) { |
649 virtual_states_[effect->id()] = | 768 virtual_states_[effect->id()] = |
650 new (zone()) VirtualState(zone(), graph()->NodeCount()); | 769 new (zone()) VirtualState(zone(), graph()->NodeCount()); |
651 } | 770 } |
652 } | 771 } |
653 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 772 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
654 if (IsEffectBranchPoint(effect)) { | 773 if (IsEffectBranchPoint(effect)) { |
655 if (virtual_states_[node->id()]) return; | 774 if (!virtual_states_[node->id()]) { |
656 virtual_states_[node->id()] = | 775 virtual_states_[node->id()] = |
657 new (zone()) VirtualState(*virtual_states_[effect->id()]); | 776 new (zone()) VirtualState(*virtual_states_[effect->id()]); |
| 777 } else { |
| 778 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
| 779 zone()); |
| 780 } |
658 if (FLAG_trace_turbo_escape) { | 781 if (FLAG_trace_turbo_escape) { |
659 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | 782 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", |
660 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 783 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
661 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 784 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
662 } | 785 } |
663 } else { | 786 } else { |
664 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 787 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
665 if (FLAG_trace_turbo_escape) { | 788 if (FLAG_trace_turbo_escape) { |
666 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | 789 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", |
667 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 790 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
668 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 791 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
669 } | 792 } |
670 } | 793 } |
671 } | 794 } |
672 | 795 |
673 | 796 |
674 void EscapeAnalysis::ProcessStart(Node* node) { | 797 void EscapeAnalysis::ProcessStart(Node* node) { |
675 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 798 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
676 virtual_states_[node->id()] = | 799 virtual_states_[node->id()] = |
677 new (zone()) VirtualState(zone(), graph()->NodeCount()); | 800 new (zone()) VirtualState(zone(), graph()->NodeCount()); |
678 } | 801 } |
679 | 802 |
680 | 803 |
681 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 804 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
682 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 805 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
683 // For now only support binary phis. | 806 // For now only support binary phis. |
684 DCHECK_EQ(node->op()->EffectInputCount(), 2); | 807 CHECK_EQ(node->op()->EffectInputCount(), 2); |
685 Node* left = NodeProperties::GetEffectInput(node, 0); | 808 Node* left = NodeProperties::GetEffectInput(node, 0); |
686 Node* right = NodeProperties::GetEffectInput(node, 1); | 809 Node* right = NodeProperties::GetEffectInput(node, 1); |
687 bool changed = false; | 810 bool changed = false; |
688 | 811 |
689 VirtualState* mergeState = virtual_states_[node->id()]; | 812 VirtualState* mergeState = virtual_states_[node->id()]; |
690 if (!mergeState) { | 813 if (!mergeState) { |
691 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); | 814 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); |
692 virtual_states_[node->id()] = mergeState; | 815 virtual_states_[node->id()] = mergeState; |
693 changed = true; | 816 changed = true; |
694 if (FLAG_trace_turbo_escape) { | 817 if (FLAG_trace_turbo_escape) { |
695 PrintF("Phi #%d got new states map %p.\n", node->id(), | 818 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), |
696 static_cast<void*>(mergeState)); | 819 static_cast<void*>(mergeState)); |
697 } | 820 } |
698 } else if (mergeState->GetLastChanged() != node) { | 821 } else if (mergeState->GetLastChanged() != node) { |
699 changed = true; | 822 changed = true; |
700 } | 823 } |
701 | 824 |
702 VirtualState* l = virtual_states_[left->id()]; | 825 VirtualState* l = virtual_states_[left->id()]; |
703 VirtualState* r = virtual_states_[right->id()]; | 826 VirtualState* r = virtual_states_[right->id()]; |
704 | 827 |
705 if (l == nullptr && r == nullptr) { | 828 if (l == nullptr && r == nullptr) { |
706 return changed; | 829 return changed; |
707 } | 830 } |
708 | 831 |
709 if (FLAG_trace_turbo_escape) { | 832 if (FLAG_trace_turbo_escape) { |
710 PrintF("At Phi #%d, merging states %p (from #%d) and %p (from #%d)\n", | 833 PrintF( |
711 node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r), | 834 "At Effect Phi #%d, merging states %p (from #%d) and %p (from #%d) " |
712 right->id()); | 835 "into %p\n", |
| 836 node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r), |
| 837 right->id(), static_cast<void*>(mergeState)); |
713 } | 838 } |
714 | 839 |
715 if (r && l == nullptr) { | 840 if (r && l == nullptr) { |
716 changed = mergeState->UpdateFrom(r, zone()) || changed; | 841 changed = mergeState->UpdateFrom(r, zone()) || changed; |
717 } else if (l && r == nullptr) { | 842 } else if (l && r == nullptr) { |
718 changed = mergeState->UpdateFrom(l, zone()) || changed; | 843 changed = mergeState->UpdateFrom(l, zone()) || changed; |
719 } else { | 844 } else { |
720 changed = mergeState->MergeFrom(l, r, zone(), graph(), common(), | 845 changed = mergeState->MergeFrom(l, r, zone(), graph(), common(), |
721 NodeProperties::GetControlInput(node)) || | 846 NodeProperties::GetControlInput(node)) || |
722 changed; | 847 changed; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
783 bool EscapeAnalysis::IsVirtual(Node* node) { | 908 bool EscapeAnalysis::IsVirtual(Node* node) { |
784 return escape_status_.IsVirtual(node); | 909 return escape_status_.IsVirtual(node); |
785 } | 910 } |
786 | 911 |
787 | 912 |
788 bool EscapeAnalysis::IsEscaped(Node* node) { | 913 bool EscapeAnalysis::IsEscaped(Node* node) { |
789 return escape_status_.IsEscaped(node); | 914 return escape_status_.IsEscaped(node); |
790 } | 915 } |
791 | 916 |
792 | 917 |
| 918 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
| 919 if (VirtualState* states = virtual_states_[at->id()]) { |
| 920 return states->GetVirtualObject(id); |
| 921 } |
| 922 return nullptr; |
| 923 } |
| 924 |
| 925 |
793 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 926 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
794 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 927 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
795 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 928 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
796 } | 929 } |
797 | 930 |
798 | 931 |
| 932 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
| 933 VirtualState* state) { |
| 934 // Only binary phis are supported for now. |
| 935 CHECK_EQ(from->op()->ValueInputCount(), 2); |
| 936 if (FLAG_trace_turbo_escape) { |
| 937 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
| 938 } |
| 939 Node* left = NodeProperties::GetValueInput(from, 0); |
| 940 Node* right = NodeProperties::GetValueInput(from, 1); |
| 941 VirtualObject* l = state->GetVirtualObject(left); |
| 942 VirtualObject* r = state->GetVirtualObject(right); |
| 943 if (l && r) { |
| 944 Node* lv = l->GetField(offset); |
| 945 Node* rv = r->GetField(offset); |
| 946 if (lv && rv) { |
| 947 if (!state->GetVirtualObject(node)) { |
| 948 state->SetVirtualObject(node->id(), |
| 949 new (zone()) VirtualObject(node->id(), zone())); |
| 950 } |
| 951 Node* rep = state->GetVirtualObject(node)->GetReplacement(); |
| 952 if (!rep || rep->opcode() != IrOpcode::kPhi || |
| 953 NodeProperties::GetValueInput(rep, 0) != lv || |
| 954 NodeProperties::GetValueInput(rep, 1) != rv) { |
| 955 Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv, |
| 956 NodeProperties::GetControlInput(from)); |
| 957 state->GetVirtualObject(node)->SetReplacement(phi); |
| 958 state->LastChangedAt(node); |
| 959 if (FLAG_trace_turbo_escape) { |
| 960 PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id()); |
| 961 } |
| 962 } else if (FLAG_trace_turbo_escape) { |
| 963 PrintF(" has already the right phi representation.\n"); |
| 964 } |
| 965 } else if (FLAG_trace_turbo_escape) { |
| 966 PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv), |
| 967 static_cast<void*>(rv)); |
| 968 } |
| 969 } else if (FLAG_trace_turbo_escape) { |
| 970 PrintF(" has incomplete virtual object info: %p %p\n", |
| 971 static_cast<void*>(l), static_cast<void*>(r)); |
| 972 } |
| 973 } |
| 974 |
| 975 |
799 void EscapeAnalysis::ProcessLoadField(Node* node) { | 976 void EscapeAnalysis::ProcessLoadField(Node* node) { |
800 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 977 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
801 ForwardVirtualState(node); | 978 ForwardVirtualState(node); |
802 Node* from = NodeProperties::GetValueInput(node, 0); | 979 Node* from = NodeProperties::GetValueInput(node, 0); |
803 int offset = OffsetFromAccess(node); | 980 VirtualState* state = virtual_states_[node->id()]; |
804 VirtualState* states = virtual_states_[node->id()]; | 981 if (VirtualObject* object = state->ResolveVirtualObject(from)) { |
805 if (VirtualObject* state = states->GetVirtualObject(from)) { | 982 int offset = OffsetFromAccess(node); |
806 if (!state->IsTracked()) return; | 983 if (!object->IsTracked()) return; |
807 Node* value = state->GetField(offset); | 984 Node* value = object->GetField(offset); |
808 if (value) { | 985 if (value) { |
| 986 value = state->ResolveReplacement(value); |
809 // Record that the load has this alias. | 987 // Record that the load has this alias. |
810 states->UpdateReplacement(node, value, zone()); | 988 state->UpdateReplacement(node, value, zone()); |
811 } else if (FLAG_trace_turbo_escape) { | 989 } else if (FLAG_trace_turbo_escape) { |
812 PrintF("No field %d on record for #%d\n", offset, from->id()); | 990 PrintF("No field %d on record for #%d\n", offset, from->id()); |
813 } | 991 } |
814 } else { | 992 } else { |
815 if (from->opcode() == IrOpcode::kPhi) { | 993 if (from->opcode() == IrOpcode::kPhi) { |
| 994 int offset = OffsetFromAccess(node); |
816 // Only binary phis are supported for now. | 995 // Only binary phis are supported for now. |
817 CHECK_EQ(from->op()->ValueInputCount(), 2); | 996 ProcessLoadFromPhi(offset, from, node, state); |
818 if (FLAG_trace_turbo_escape) { | 997 } |
819 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 998 } |
| 999 } |
| 1000 |
| 1001 |
| 1002 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
| 1003 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
| 1004 ForwardVirtualState(node); |
| 1005 Node* from = NodeProperties::GetValueInput(node, 0); |
| 1006 VirtualState* state = virtual_states_[node->id()]; |
| 1007 if (VirtualObject* object = state->ResolveVirtualObject(from)) { |
| 1008 NumberMatcher index(node->InputAt(1)); |
| 1009 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1010 if (index.HasValue()) { |
| 1011 CHECK_EQ(ElementSizeLog2Of(access.machine_type), kPointerSizeLog2); |
| 1012 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1013 int offset = index.Value() + access.header_size / kPointerSize; |
| 1014 if (!object->IsTracked()) return; |
| 1015 Node* value = object->GetField(offset); |
| 1016 if (value) { |
| 1017 value = state->ResolveReplacement(value); |
| 1018 // Record that the load has this alias. |
| 1019 state->UpdateReplacement(node, value, zone()); |
| 1020 } else if (FLAG_trace_turbo_escape) { |
| 1021 PrintF("No field %d on record for #%d\n", offset, from->id()); |
820 } | 1022 } |
821 Node* left = NodeProperties::GetValueInput(from, 0); | 1023 } |
822 Node* right = NodeProperties::GetValueInput(from, 1); | 1024 } else { |
823 VirtualObject* l = states->GetVirtualObject(left); | 1025 if (from->opcode() == IrOpcode::kPhi) { |
824 VirtualObject* r = states->GetVirtualObject(right); | 1026 NumberMatcher index(node->InputAt(1)); |
825 if (l && r) { | 1027 ElementAccess access = OpParameter<ElementAccess>(node); |
826 Node* lv = l->GetField(offset); | 1028 int offset = index.Value() + access.header_size / kPointerSize; |
827 Node* rv = r->GetField(offset); | 1029 if (index.HasValue()) { |
828 if (lv && rv) { | 1030 ProcessLoadFromPhi(offset, from, node, state); |
829 if (!states->GetVirtualObject(node)) { | |
830 states->SetVirtualObject( | |
831 node->id(), new (zone()) VirtualObject(node->id(), zone())); | |
832 } | |
833 Node* rep = states->GetVirtualObject(node)->GetReplacement(); | |
834 if (!rep || rep->opcode() != IrOpcode::kPhi || | |
835 NodeProperties::GetValueInput(rep, 0) != lv || | |
836 NodeProperties::GetValueInput(rep, 1) != rv) { | |
837 Node* phi = | |
838 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv, | |
839 NodeProperties::GetControlInput(from)); | |
840 states->GetVirtualObject(node)->SetReplacement(phi); | |
841 states->LastChangedAt(node); | |
842 if (FLAG_trace_turbo_escape) { | |
843 PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id()); | |
844 } | |
845 } else if (FLAG_trace_turbo_escape) { | |
846 PrintF(" has already the right phi representation.\n"); | |
847 } | |
848 } else if (FLAG_trace_turbo_escape) { | |
849 PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv), | |
850 static_cast<void*>(rv)); | |
851 } | |
852 } else if (FLAG_trace_turbo_escape) { | |
853 PrintF(" has incomplete virtual object info: %p %p\n", | |
854 static_cast<void*>(l), static_cast<void*>(r)); | |
855 } | 1031 } |
856 } | 1032 } |
857 } | 1033 } |
858 } | 1034 } |
859 | 1035 |
860 | 1036 |
861 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1037 void EscapeAnalysis::ProcessStoreField(Node* node) { |
862 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1038 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
863 ForwardVirtualState(node); | 1039 ForwardVirtualState(node); |
864 Node* to = NodeProperties::GetValueInput(node, 0); | 1040 Node* to = NodeProperties::GetValueInput(node, 0); |
865 Node* val = NodeProperties::GetValueInput(node, 1); | 1041 Node* val = NodeProperties::GetValueInput(node, 1); |
866 int offset = OffsetFromAccess(node); | 1042 int offset = OffsetFromAccess(node); |
867 VirtualState* states = virtual_states_[node->id()]; | 1043 VirtualState* states = virtual_states_[node->id()]; |
868 if (VirtualObject* obj = states->GetVirtualObject(to)) { | 1044 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { |
869 if (!obj->IsTracked()) return; | 1045 if (!obj->IsTracked()) return; |
870 if (obj->SetField(offset, states->ResolveReplacement(val))) { | 1046 if (obj->SetField(offset, states->ResolveReplacement(val))) { |
871 states->LastChangedAt(node); | 1047 states->LastChangedAt(node); |
872 } | 1048 } |
873 } | 1049 } |
874 } | 1050 } |
875 | 1051 |
876 | 1052 |
| 1053 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
| 1054 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
| 1055 ForwardVirtualState(node); |
| 1056 Node* to = NodeProperties::GetValueInput(node, 0); |
| 1057 NumberMatcher index(node->InputAt(1)); |
| 1058 ElementAccess access = OpParameter<ElementAccess>(node); |
| 1059 Node* val = NodeProperties::GetValueInput(node, 2); |
| 1060 if (index.HasValue()) { |
| 1061 CHECK_EQ(ElementSizeLog2Of(access.machine_type), kPointerSizeLog2); |
| 1062 CHECK_EQ(access.header_size % kPointerSize, 0); |
| 1063 int offset = index.Value() + access.header_size / kPointerSize; |
| 1064 VirtualState* states = virtual_states_[node->id()]; |
| 1065 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { |
| 1066 if (!obj->IsTracked()) return; |
| 1067 if (obj->SetField(offset, states->ResolveReplacement(val))) { |
| 1068 states->LastChangedAt(node); |
| 1069 } |
| 1070 } |
| 1071 } |
| 1072 } |
| 1073 |
| 1074 |
| 1075 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { |
| 1076 PrintF(" Object #%d with %zu fields", id, object->field_count()); |
| 1077 if (Node* rep = object->GetReplacement()) { |
| 1078 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); |
| 1079 } |
| 1080 PrintF("\n"); |
| 1081 for (size_t i = 0; i < object->field_count(); ++i) { |
| 1082 if (Node* f = object->GetField(i)) { |
| 1083 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
| 1084 } |
| 1085 } |
| 1086 } |
| 1087 |
| 1088 |
| 1089 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
| 1090 PrintF("Dumping object state %p\n", static_cast<void*>(state)); |
| 1091 for (size_t id = 0; id < state->size(); id++) { |
| 1092 if (VirtualObject* object = state->GetVirtualObject(id)) { |
| 1093 if (object->id() == id) { |
| 1094 DebugPrintObject(object, static_cast<int>(id)); |
| 1095 } else { |
| 1096 PrintF(" Object #%zu links to object #%d\n", id, object->id()); |
| 1097 } |
| 1098 } |
| 1099 } |
| 1100 } |
| 1101 |
| 1102 |
877 void EscapeAnalysis::DebugPrint() { | 1103 void EscapeAnalysis::DebugPrint() { |
878 ZoneVector<VirtualState*> object_states(zone()); | 1104 ZoneVector<VirtualState*> object_states(zone()); |
879 for (NodeId id = 0; id < virtual_states_.size(); id++) { | 1105 for (NodeId id = 0; id < virtual_states_.size(); id++) { |
880 if (VirtualState* states = virtual_states_[id]) { | 1106 if (VirtualState* states = virtual_states_[id]) { |
881 if (std::find(object_states.begin(), object_states.end(), states) == | 1107 if (std::find(object_states.begin(), object_states.end(), states) == |
882 object_states.end()) { | 1108 object_states.end()) { |
883 object_states.push_back(states); | 1109 object_states.push_back(states); |
884 } | 1110 } |
885 } | 1111 } |
886 } | 1112 } |
887 for (size_t n = 0; n < object_states.size(); n++) { | 1113 for (size_t n = 0; n < object_states.size(); n++) { |
888 PrintF("Dumping object state %p\n", static_cast<void*>(object_states[n])); | 1114 DebugPrintState(object_states[n]); |
889 for (size_t id = 0; id < object_states[n]->size(); id++) { | |
890 if (VirtualObject* obj = object_states[n]->GetVirtualObject(id)) { | |
891 if (obj->id() == id) { | |
892 PrintF(" Object #%zu with %zu fields", id, obj->fields()); | |
893 if (Node* rep = obj->GetReplacement()) { | |
894 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); | |
895 } | |
896 PrintF("\n"); | |
897 for (size_t i = 0; i < obj->fields(); ++i) { | |
898 if (Node* f = obj->GetField(i)) { | |
899 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), | |
900 f->op()->mnemonic()); | |
901 } | |
902 } | |
903 } else { | |
904 PrintF(" Object #%zu links to object #%d\n", id, obj->id()); | |
905 } | |
906 } | |
907 } | |
908 } | 1115 } |
909 } | 1116 } |
910 | 1117 |
911 } // namespace compiler | 1118 } // namespace compiler |
912 } // namespace internal | 1119 } // namespace internal |
913 } // namespace v8 | 1120 } // namespace v8 |
OLD | NEW |