| 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 |