Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Side by Side Diff: src/compiler/escape-analysis.cc

Issue 1510973006: Stabilize escape analysis (without deopt) (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@fix-guard-bug
Patch Set: Rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 11 matching lines...) Expand all
22 namespace compiler { 22 namespace compiler {
23 23
24 24
25 // ------------------------------VirtualObject---------------------------------- 25 // ------------------------------VirtualObject----------------------------------
26 26
27 27
28 class VirtualObject : public ZoneObject { 28 class VirtualObject : public ZoneObject {
29 public: 29 public:
30 enum Status { kUntracked = 0, kTracked = 1 }; 30 enum Status { kUntracked = 0, kTracked = 1 };
31 VirtualObject(NodeId id, Zone* zone) 31 VirtualObject(NodeId id, Zone* zone)
32 : id_(id), status_(kUntracked), fields_(zone), replacement_(nullptr) {} 32 : id_(id),
33 status_(kUntracked),
34 fields_(zone),
35 phi_(zone),
36 replacement_(nullptr) {}
33 37
34 VirtualObject(const VirtualObject& other) 38 VirtualObject(const VirtualObject& other)
35 : id_(other.id_), 39 : id_(other.id_),
36 status_(other.status_), 40 status_(other.status_),
37 fields_(other.fields_), 41 fields_(other.fields_),
42 phi_(other.phi_),
38 replacement_(other.replacement_) {} 43 replacement_(other.replacement_) {}
39 44
40 VirtualObject(NodeId id, Zone* zone, size_t field_number) 45 VirtualObject(NodeId id, Zone* zone, size_t field_number)
41 : id_(id), status_(kTracked), fields_(zone), replacement_(nullptr) { 46 : id_(id),
47 status_(kTracked),
48 fields_(zone),
49 phi_(zone),
50 replacement_(nullptr) {
42 fields_.resize(field_number); 51 fields_.resize(field_number);
52 phi_.resize(field_number, false);
43 } 53 }
44 54
45 Node* GetField(size_t offset) { 55 Node* GetField(size_t offset) {
46 if (offset < fields_.size()) { 56 if (offset < fields_.size()) {
47 return fields_[offset]; 57 return fields_[offset];
48 } 58 }
49 return nullptr; 59 return nullptr;
50 } 60 }
51 61
52 bool SetField(size_t offset, Node* node) { 62 bool IsCreatedPhi(size_t offset) {
53 bool changed = fields_[offset] != node; 63 if (offset < phi_.size()) {
64 return phi_[offset];
65 }
66 return false;
67 }
68
69 bool SetField(size_t offset, Node* node, bool created_phi = false) {
70 bool changed = fields_[offset] != node || phi_[offset] != created_phi;
54 fields_[offset] = node; 71 fields_[offset] = node;
72 phi_[offset] = created_phi;
73 if (changed && FLAG_trace_turbo_escape && node) {
74 PrintF("Setting field %zu of #%d to #%d (%s)\n", offset, id(), node->id(),
75 node->op()->mnemonic());
76 }
55 return changed; 77 return changed;
56 } 78 }
57 bool IsVirtual() const { return status_ == kTracked; } 79 bool IsVirtual() const { return status_ == kTracked; }
58 bool IsTracked() const { return status_ != kUntracked; } 80 bool IsTracked() const { return status_ != kUntracked; }
59 Node* GetReplacement() { return replacement_; } 81 Node* GetReplacement() { return replacement_; }
60 bool SetReplacement(Node* node) { 82 bool SetReplacement(Node* node) {
61 bool changed = replacement_ != node; 83 bool changed = replacement_ != node;
62 replacement_ = node; 84 replacement_ = node;
63 return changed; 85 return changed;
64 } 86 }
65 87
66 Node** fields_array() { return &fields_.front(); } 88 Node** fields_array() { return &fields_.front(); }
67 size_t field_count() { return fields_.size(); } 89 size_t field_count() { return fields_.size(); }
68 bool ResizeFields(size_t field_count) { 90 bool ResizeFields(size_t field_count) {
69 if (field_count != fields_.size()) { 91 if (field_count != fields_.size()) {
70 fields_.resize(field_count); 92 fields_.resize(field_count);
93 phi_.resize(field_count);
71 return true; 94 return true;
72 } 95 }
73 return false; 96 return false;
74 } 97 }
75 bool ClearAllFields() { 98 bool ClearAllFields() {
76 bool changed = false; 99 bool changed = false;
77 for (size_t i = 0; i < fields_.size(); ++i) { 100 for (size_t i = 0; i < fields_.size(); ++i) {
78 if (fields_[i] != nullptr) { 101 if (fields_[i] != nullptr) {
79 fields_[i] = nullptr; 102 fields_[i] = nullptr;
80 changed = true; 103 changed = true;
81 } 104 }
105 phi_[i] = false;
82 } 106 }
83 return changed; 107 return changed;
84 } 108 }
85 bool UpdateFrom(const VirtualObject& other); 109 bool UpdateFrom(const VirtualObject& other);
86 110
87 NodeId id() { return id_; } 111 NodeId id() { return id_; }
88 void id(NodeId id) { id_ = id; } 112 void id(NodeId id) { id_ = id; }
89 113
90 private: 114 private:
91 NodeId id_; 115 NodeId id_;
92 Status status_; 116 Status status_;
93 ZoneVector<Node*> fields_; 117 ZoneVector<Node*> fields_;
118 ZoneVector<bool> phi_;
94 Node* replacement_; 119 Node* replacement_;
95 }; 120 };
96 121
97 122
98 bool VirtualObject::UpdateFrom(const VirtualObject& other) { 123 bool VirtualObject::UpdateFrom(const VirtualObject& other) {
99 bool changed = status_ != other.status_; 124 bool changed = status_ != other.status_;
100 status_ = other.status_; 125 status_ = other.status_;
101 changed = replacement_ != other.replacement_ || changed; 126 changed = replacement_ != other.replacement_ || changed;
102 replacement_ = other.replacement_; 127 replacement_ = other.replacement_;
103 if (fields_.size() != other.fields_.size()) { 128 if (fields_.size() != other.fields_.size()) {
(...skipping 22 matching lines...) Expand all
126 VirtualObject* GetVirtualObject(Node* node); 151 VirtualObject* GetVirtualObject(Node* node);
127 VirtualObject* GetVirtualObject(size_t id); 152 VirtualObject* GetVirtualObject(size_t id);
128 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); 153 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone);
129 void SetVirtualObject(NodeId id, VirtualObject* state); 154 void SetVirtualObject(NodeId id, VirtualObject* state);
130 void LastChangedAt(Node* node) { last_changed_ = node; } 155 void LastChangedAt(Node* node) { last_changed_ = node; }
131 Node* GetLastChanged() { return last_changed_; } 156 Node* GetLastChanged() { return last_changed_; }
132 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone); 157 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone);
133 Node* ResolveReplacement(Node* node); 158 Node* ResolveReplacement(Node* node);
134 bool UpdateReplacement(Node* node, Node* rep, Zone* zone); 159 bool UpdateReplacement(Node* node, Node* rep, Zone* zone);
135 bool UpdateFrom(VirtualState* state, Zone* zone); 160 bool UpdateFrom(VirtualState* state, Zone* zone);
136 bool MergeFrom(VirtualState* left, VirtualState* right, Zone* zone, 161 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
137 Graph* graph, CommonOperatorBuilder* common, Node* control); 162 CommonOperatorBuilder* common, Node* control);
138 163
139 size_t size() { return info_.size(); } 164 size_t size() { return info_.size(); }
140 165
141 private: 166 private:
142 ZoneVector<VirtualObject*> info_; 167 ZoneVector<VirtualObject*> info_;
143 Node* last_changed_; 168 Node* last_changed_;
144 }; 169 };
145 170
146 171
147 VirtualState::VirtualState(Zone* zone, size_t size) 172 VirtualState::VirtualState(Zone* zone, size_t size)
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 static_cast<void*>(fromObj)); 248 static_cast<void*>(fromObj));
224 } 249 }
225 return true; 250 return true;
226 } 251 }
227 252
228 return false; 253 return false;
229 } 254 }
230 255
231 256
232 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { 257 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
233 DCHECK_EQ(size(), from->size());
234 bool changed = false; 258 bool changed = false;
235 for (NodeId id = 0; id < size(); ++id) { 259 for (NodeId id = 0; id < size(); ++id) {
236 VirtualObject* ls = GetVirtualObject(id); 260 VirtualObject* ls = GetVirtualObject(id);
237 VirtualObject* rs = from->GetVirtualObject(id); 261 VirtualObject* rs = from->GetVirtualObject(id);
238 262
239 if (rs == nullptr) { 263 if (rs == nullptr) {
240 continue; 264 continue;
241 } 265 }
242 266
243 if (ls == nullptr) { 267 if (ls == nullptr) {
244 ls = new (zone) VirtualObject(*rs); 268 ls = new (zone) VirtualObject(*rs);
245 SetVirtualObject(id, ls); 269 SetVirtualObject(id, ls);
246 changed = true; 270 changed = true;
247 continue; 271 continue;
248 } 272 }
249 273
250 if (FLAG_trace_turbo_escape) { 274 if (FLAG_trace_turbo_escape) {
251 PrintF(" Updating fields of #%d\n", id); 275 PrintF(" Updating fields of #%d\n", id);
252 } 276 }
253 277
254 changed = ls->UpdateFrom(*rs) || changed; 278 changed = ls->UpdateFrom(*rs) || changed;
255 } 279 }
256 return false; 280 return false;
257 } 281 }
258 282
259 283
260 bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right, 284 namespace {
261 Zone* zone, Graph* graph, 285
286 size_t min_size(ZoneVector<VirtualState*>& states) {
287 size_t min = SIZE_MAX;
288 for (VirtualState* state : states) {
289 min = std::min(state->size(), min);
290 }
291 return min;
292 }
293
294
295 size_t min_field_count(ZoneVector<VirtualObject*>& objs) {
296 size_t min = SIZE_MAX;
297 for (VirtualObject* obj : objs) {
298 min = std::min(obj->field_count(), min);
299 }
300 return min;
301 }
302
303
304 void GetVirtualObjects(ZoneVector<VirtualState*> states,
305 ZoneVector<VirtualObject*>& objs, NodeId id) {
306 objs.clear();
307 for (VirtualState* state : states) {
308 if (VirtualObject* obj = state->GetVirtualObject(id)) {
309 objs.push_back(obj);
310 }
311 }
312 }
313
314
315 void GetVirtualObjects(VirtualState* state, ZoneVector<Node*> nodes,
316 ZoneVector<VirtualObject*>& objs) {
317 objs.clear();
318 for (Node* node : nodes) {
319 if (VirtualObject* obj = state->GetVirtualObject(node)) {
320 objs.push_back(obj);
321 }
322 }
323 }
324
325
326 Node* GetFieldIfSame(size_t pos, ZoneVector<VirtualObject*>& objs) {
327 Node* rep = objs.front()->GetField(pos);
328 for (VirtualObject* obj : objs) {
329 if (obj->GetField(pos) != rep) {
330 return nullptr;
331 }
332 }
333 return rep;
334 }
335
336
337 Node* GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) {
338 Node* rep = objs.front()->GetReplacement();
339 for (VirtualObject* obj : objs) {
340 if (obj->GetReplacement() != rep) {
341 return nullptr;
342 }
343 }
344 return rep;
345 }
346
347
348 void GetFields(ZoneVector<VirtualObject*>& objs, ZoneVector<Node*>& fields,
349 size_t pos) {
350 fields.clear();
351 for (VirtualObject* obj : objs) {
352 if (Node* field = obj->GetField(pos)) {
353 fields.push_back(field);
354 }
355 }
356 }
357
358
359 bool IsEquivalentPhi(Node* node1, Node* node2) {
360 if (node1 == node2) return true;
361 if (node1->opcode() != IrOpcode::kPhi || node2->opcode() != IrOpcode::kPhi ||
362 node1->op()->ValueInputCount() != node2->op()->ValueInputCount()) {
363 return false;
364 }
365 for (int i = 0; i < node1->op()->ValueInputCount(); ++i) {
366 Node* input1 = NodeProperties::GetValueInput(node1, i);
367 Node* input2 = NodeProperties::GetValueInput(node2, i);
368 if (!IsEquivalentPhi(input1, input2)) {
369 return false;
370 }
371 }
372 return true;
373 }
374
375
376 bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) {
377 if (phi->opcode() != IrOpcode::kPhi) return false;
378 if (phi->op()->ValueInputCount() != inputs.size()) {
379 return false;
380 }
381 for (size_t i = 0; i < inputs.size(); ++i) {
382 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i));
383 if (!IsEquivalentPhi(input, inputs[i])) {
384 return false;
385 }
386 }
387 return true;
388 }
389
390 } // namespace
391
392
393 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
262 CommonOperatorBuilder* common, Node* control) { 394 CommonOperatorBuilder* common, Node* control) {
395 DCHECK_GT(cache->states().size(), 0u);
263 bool changed = false; 396 bool changed = false;
264 for (NodeId id = 0; id < std::min(left->size(), right->size()); ++id) { 397 for (NodeId id = 0; id < min_size(cache->states()); ++id) {
265 VirtualObject* ls = left->GetVirtualObject(id); 398 GetVirtualObjects(cache->states(), cache->objects(), id);
266 VirtualObject* rs = right->GetVirtualObject(id); 399 if (cache->objects().size() == cache->states().size()) {
267 400 // Don't process linked objects.
268 if (ls != nullptr && rs != nullptr) { 401 if (cache->objects()[0]->id() != id) continue;
269 if (FLAG_trace_turbo_escape) { 402 if (FLAG_trace_turbo_escape) {
270 PrintF(" Merging fields of #%d\n", id); 403 PrintF(" Merging virtual objects of #%d\n", id);
271 } 404 }
272 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); 405 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
273 size_t fields = std::max(ls->field_count(), rs->field_count()); 406 mergeObject->SetReplacement(GetReplacementIfSame(cache->objects()));
407 size_t fields = min_field_count(cache->objects());
274 changed = mergeObject->ResizeFields(fields) || changed; 408 changed = mergeObject->ResizeFields(fields) || changed;
275 for (size_t i = 0; i < fields; ++i) { 409 for (size_t i = 0; i < fields; ++i) {
276 if (ls->GetField(i) == rs->GetField(i)) { 410 if (Node* field = GetFieldIfSame(i, cache->objects())) {
277 changed = mergeObject->SetField(i, ls->GetField(i)) || changed; 411 changed = mergeObject->SetField(i, field) || changed;
278 if (FLAG_trace_turbo_escape && ls->GetField(i)) { 412 if (FLAG_trace_turbo_escape) {
279 PrintF(" Field %zu agree on rep #%d\n", i, 413 PrintF(" Field %zu agree on rep #%d\n", i, field->id());
280 ls->GetField(i)->id());
281 } 414 }
282 } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) { 415 } else {
283 Node* rep = mergeObject->GetField(i); 416 GetFields(cache->objects(), cache->fields(), i);
284 if (!rep || rep->opcode() != IrOpcode::kPhi || 417 if (cache->fields().size() == cache->objects().size()) {
285 NodeProperties::GetValueInput(rep, 0) != ls->GetField(i) || 418 Node* rep = mergeObject->GetField(i);
286 NodeProperties::GetValueInput(rep, 1) != rs->GetField(i)) { 419 if (!rep || !mergeObject->IsCreatedPhi(i)) {
287 Node* phi = 420 cache->fields().push_back(control);
288 graph->NewNode(common->Phi(MachineRepresentation::kTagged, 2), 421 Node* phi =
289 ls->GetField(i), rs->GetField(i), control); 422 graph->NewNode(common->Phi(MachineRepresentation::kTagged, 2),
290 if (mergeObject->SetField(i, phi)) { 423 static_cast<int>(cache->fields().size()),
291 if (FLAG_trace_turbo_escape) { 424 &cache->fields().front());
292 PrintF(" Creating Phi #%d as merge of #%d and #%d\n", 425 if (mergeObject->SetField(i, phi, true)) {
293 phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id()); 426 if (FLAG_trace_turbo_escape) {
427 PrintF(" Creating Phi #%d as merge of", phi->id());
428 for (size_t i = 0; i + 1 < cache->fields().size(); i++) {
429 PrintF(" #%d (%s)", cache->fields()[i]->id(),
430 cache->fields()[i]->op()->mnemonic());
431 }
432 PrintF("\n");
433 }
434 changed = true;
294 } 435 }
295 changed = true; 436 } else {
437 DCHECK(rep->opcode() == IrOpcode::kPhi);
438 for (size_t n = 0; n < cache->fields().size(); ++n) {
439 Node* old =
440 NodeProperties::GetValueInput(rep, static_cast<int>(n));
441 if (old != cache->fields()[n]) {
442 changed = true;
443 NodeProperties::ReplaceValueInput(rep, cache->fields()[n],
444 static_cast<int>(n));
445 }
446 }
296 } 447 }
297 } else { 448 } else {
298 if (FLAG_trace_turbo_escape) { 449 changed = mergeObject->SetField(i, nullptr) || changed;
299 PrintF(" Retaining Phi #%d as merge of #%d and #%d\n",
300 rep->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
301 }
302 } 450 }
303 } else {
304 changed = mergeObject->SetField(i, nullptr) || changed;
305 } 451 }
306 } 452 }
307 } else if (ls) { 453
308 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); 454 } else {
309 changed = mergeObject->UpdateFrom(*ls) || changed; 455 SetVirtualObject(id, nullptr);
310 } else if (rs) { 456 }
311 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); 457 }
312 changed = mergeObject->UpdateFrom(*rs) || changed; 458 // Update linked objects.
459 for (NodeId id = 0; id < min_size(cache->states()); ++id) {
460 GetVirtualObjects(cache->states(), cache->objects(), id);
461 if (cache->objects().size() == cache->states().size()) {
462 if (cache->objects()[0]->id() != id) {
463 SetVirtualObject(id, GetVirtualObject(cache->objects()[0]->id()));
464 }
313 } 465 }
314 } 466 }
315 return changed; 467 return changed;
316 } 468 }
317 469
318 470
319 Node* VirtualState::ResolveReplacement(Node* node) { 471 Node* VirtualState::ResolveReplacement(Node* node) {
320 Node* replacement = node; 472 Node* replacement = node;
321 VirtualObject* obj = GetVirtualObject(node); 473 VirtualObject* obj = GetVirtualObject(node);
322 while (obj != nullptr && obj->GetReplacement()) { 474 while (obj != nullptr && obj->GetReplacement()) {
323 replacement = obj->GetReplacement(); 475 replacement = obj->GetReplacement();
324 obj = GetVirtualObject(replacement); 476 obj = GetVirtualObject(replacement);
325 } 477 }
326 return replacement; 478 return replacement;
327 } 479 }
328 480
329 481
330 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) { 482 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) {
331 if (!GetVirtualObject(node)) { 483 if (!GetVirtualObject(node)) {
332 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone)); 484 if (rep) {
485 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone));
486 } else {
487 return false;
488 }
333 } 489 }
334 if (GetVirtualObject(node)->SetReplacement(rep)) { 490 if (GetVirtualObject(node)->SetReplacement(rep)) {
335 LastChangedAt(node); 491 LastChangedAt(node);
336 if (FLAG_trace_turbo_escape) { 492 if (FLAG_trace_turbo_escape) {
337 PrintF("Representation of #%d is #%d (%s)\n", node->id(), rep->id(), 493 if (rep) {
338 rep->op()->mnemonic()); 494 PrintF("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(),
495 rep->op()->mnemonic());
496 } else {
497 PrintF("Replacement of #%d cleared\n", node->id());
498 }
339 } 499 }
340 return true; 500 return true;
341 } 501 }
342 return false; 502 return false;
343 } 503 }
344 504
345 505
346 // ------------------------------EscapeStatusAnalysis--------------------------- 506 // ------------------------------EscapeStatusAnalysis---------------------------
347 507
348 508
349 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, 509 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
350 Graph* graph, Zone* zone) 510 Graph* graph, Zone* zone)
351 : object_analysis_(object_analysis), 511 : object_analysis_(object_analysis),
352 graph_(graph), 512 graph_(graph),
353 zone_(zone), 513 zone_(zone),
354 info_(zone), 514 info_(zone),
355 queue_(zone) {} 515 queue_(zone) {
516 info_.resize(graph->NodeCount());
517 }
356 518
357 519
358 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} 520 EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
359 521
360 522
361 bool EscapeStatusAnalysis::HasEntry(Node* node) { 523 bool EscapeStatusAnalysis::HasEntry(Node* node) {
362 return info_[node->id()] != kUnknown; 524 return info_[node->id()] != kUnknown;
363 } 525 }
364 526
365 527
366 bool EscapeStatusAnalysis::IsVirtual(Node* node) { 528 bool EscapeStatusAnalysis::IsVirtual(Node* node) {
367 if (node->id() >= info_.size()) { 529 if (node->id() >= info_.size()) {
368 return false; 530 return false;
369 } 531 }
370 return info_[node->id()] == kVirtual; 532 return info_[node->id()] == kVirtual;
371 } 533 }
372 534
373 535
374 bool EscapeStatusAnalysis::IsEscaped(Node* node) { 536 bool EscapeStatusAnalysis::IsEscaped(Node* node) {
375 return info_[node->id()] == kEscaped; 537 return info_[node->id()] == kEscaped;
376 } 538 }
377 539
378 540
541 bool EscapeStatusAnalysis::IsAllocation(Node* node) {
542 return node->opcode() == IrOpcode::kAllocate ||
543 node->opcode() == IrOpcode::kFinishRegion;
544 }
545
546
379 bool EscapeStatusAnalysis::SetEscaped(Node* node) { 547 bool EscapeStatusAnalysis::SetEscaped(Node* node) {
380 bool changed = info_[node->id()] != kEscaped; 548 bool changed = info_[node->id()] != kEscaped;
381 info_[node->id()] = kEscaped; 549 info_[node->id()] = kEscaped;
382 return changed; 550 return changed;
383 } 551 }
384 552
385 553
386 void EscapeStatusAnalysis::Run() { 554 void EscapeStatusAnalysis::Run() {
387 info_.resize(graph()->NodeCount()); 555 info_.resize(graph()->NodeCount());
388 ZoneVector<bool> visited(zone()); 556 ZoneVector<bool> visited(zone());
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 break; 597 break;
430 case IrOpcode::kStoreField: 598 case IrOpcode::kStoreField:
431 ProcessStoreField(node); 599 ProcessStoreField(node);
432 break; 600 break;
433 case IrOpcode::kStoreElement: 601 case IrOpcode::kStoreElement:
434 ProcessStoreElement(node); 602 ProcessStoreElement(node);
435 break; 603 break;
436 case IrOpcode::kLoadField: 604 case IrOpcode::kLoadField:
437 case IrOpcode::kLoadElement: { 605 case IrOpcode::kLoadElement: {
438 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) { 606 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) {
439 if (rep->opcode() == IrOpcode::kAllocate || 607 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) {
440 rep->opcode() == IrOpcode::kFinishRegion) { 608 RevisitInputs(rep);
441 if (CheckUsesForEscape(node, rep)) { 609 RevisitUses(rep);
442 RevisitInputs(rep);
443 RevisitUses(rep);
444 }
445 } 610 }
446 } 611 }
447 break; 612 break;
448 } 613 }
449 case IrOpcode::kPhi: 614 case IrOpcode::kPhi:
450 if (!HasEntry(node)) { 615 if (!HasEntry(node)) {
451 info_[node->id()] = kVirtual; 616 info_[node->id()] = kVirtual;
452 } 617 }
453 CheckUsesForEscape(node); 618 CheckUsesForEscape(node);
454 default: 619 default:
455 break; 620 break;
456 } 621 }
457 } 622 }
458 623
459 624
460 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { 625 void EscapeStatusAnalysis::ProcessStoreField(Node* node) {
461 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); 626 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
462 Node* to = NodeProperties::GetValueInput(node, 0); 627 Node* to = NodeProperties::GetValueInput(node, 0);
463 Node* val = NodeProperties::GetValueInput(node, 1); 628 Node* val = NodeProperties::GetValueInput(node, 1);
464 if (IsEscaped(to) && SetEscaped(val)) { 629 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
465 RevisitUses(val); 630 RevisitUses(val);
631 RevisitInputs(val);
466 if (FLAG_trace_turbo_escape) { 632 if (FLAG_trace_turbo_escape) {
467 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", 633 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
468 val->id(), val->op()->mnemonic(), to->id()); 634 val->id(), val->op()->mnemonic(), to->id());
469 } 635 }
470 } 636 }
471 } 637 }
472 638
473 639
474 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { 640 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) {
475 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); 641 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
476 Node* to = NodeProperties::GetValueInput(node, 0); 642 Node* to = NodeProperties::GetValueInput(node, 0);
477 Node* val = NodeProperties::GetValueInput(node, 2); 643 Node* val = NodeProperties::GetValueInput(node, 2);
478 if (IsEscaped(to) && SetEscaped(val)) { 644 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
479 RevisitUses(val); 645 RevisitUses(val);
646 RevisitInputs(val);
480 if (FLAG_trace_turbo_escape) { 647 if (FLAG_trace_turbo_escape) {
481 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", 648 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
482 val->id(), val->op()->mnemonic(), to->id()); 649 val->id(), val->op()->mnemonic(), to->id());
483 } 650 }
484 } 651 }
485 } 652 }
486 653
487 654
488 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { 655 void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
489 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); 656 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 if (FLAG_trace_turbo_escape) { 709 if (FLAG_trace_turbo_escape) {
543 PrintF( 710 PrintF(
544 "Setting #%d (%s) to escaped because of use by phi node " 711 "Setting #%d (%s) to escaped because of use by phi node "
545 "#%d (%s)\n", 712 "#%d (%s)\n",
546 rep->id(), rep->op()->mnemonic(), use->id(), 713 rep->id(), rep->op()->mnemonic(), use->id(),
547 use->op()->mnemonic()); 714 use->op()->mnemonic());
548 } 715 }
549 return true; 716 return true;
550 } 717 }
551 break; 718 break;
719 case IrOpcode::kObjectIsSmi:
720 if (!IsAllocation(rep) && SetEscaped(rep)) {
721 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
722 rep->id(), rep->op()->mnemonic(), use->id(),
723 use->op()->mnemonic());
724 return true;
725 }
726 break;
552 default: 727 default:
728 if (use->op()->EffectInputCount() == 0 &&
729 uses->op()->EffectInputCount() > 0) {
730 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(),
731 use->op()->mnemonic());
732 UNREACHABLE();
733 }
553 if (SetEscaped(rep)) { 734 if (SetEscaped(rep)) {
554 if (FLAG_trace_turbo_escape) { 735 if (FLAG_trace_turbo_escape) {
555 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", 736 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
556 rep->id(), rep->op()->mnemonic(), use->id(), 737 rep->id(), rep->op()->mnemonic(), use->id(),
557 use->op()->mnemonic()); 738 use->op()->mnemonic());
558 } 739 }
559 return true; 740 return true;
560 } 741 }
561 if (use->op()->EffectInputCount() == 0 &&
562 uses->op()->EffectInputCount() > 0 &&
563 uses->opcode() != IrOpcode::kLoadField) {
564 if (FLAG_trace_turbo_escape) {
565 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(),
566 use->op()->mnemonic());
567 }
568 UNREACHABLE();
569 }
570 } 742 }
571 } 743 }
572 return false; 744 return false;
573 } 745 }
574 746
575 747
576 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { 748 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
577 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); 749 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
578 if (!HasEntry(node)) { 750 if (!HasEntry(node)) {
579 info_[node->id()] = kVirtual; 751 info_[node->id()] = kVirtual;
(...skipping 17 matching lines...) Expand all
597 769
598 // -----------------------------EscapeAnalysis---------------------------------- 770 // -----------------------------EscapeAnalysis----------------------------------
599 771
600 772
601 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, 773 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
602 Zone* zone) 774 Zone* zone)
603 : graph_(graph), 775 : graph_(graph),
604 common_(common), 776 common_(common),
605 zone_(zone), 777 zone_(zone),
606 virtual_states_(zone), 778 virtual_states_(zone),
607 escape_status_(this, graph, zone) {} 779 escape_status_(this, graph, zone),
780 cache_(zone) {}
608 781
609 782
610 EscapeAnalysis::~EscapeAnalysis() {} 783 EscapeAnalysis::~EscapeAnalysis() {}
611 784
612 785
613 void EscapeAnalysis::Run() { 786 void EscapeAnalysis::Run() {
614 RunObjectAnalysis(); 787 RunObjectAnalysis();
615 escape_status_.Run(); 788 escape_status_.Run();
616 } 789 }
617 790
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
651 } 824 }
652 if (FLAG_trace_turbo_escape) { 825 if (FLAG_trace_turbo_escape) {
653 DebugPrint(); 826 DebugPrint();
654 } 827 }
655 } 828 }
656 829
657 830
658 bool EscapeAnalysis::IsDanglingEffectNode(Node* node) { 831 bool EscapeAnalysis::IsDanglingEffectNode(Node* node) {
659 if (node->op()->EffectInputCount() == 0) return false; 832 if (node->op()->EffectInputCount() == 0) return false;
660 if (node->op()->EffectOutputCount() == 0) return false; 833 if (node->op()->EffectOutputCount() == 0) return false;
834 if (node->op()->EffectInputCount() == 1 &&
835 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart) {
836 // The start node is used as sentinel for nodes that are in general
837 // effectful, but of which an analysis has determined that they do not
838 // produce effects in this instance. We don't consider these nodes dangling.
839 return false;
840 }
661 for (Edge edge : node->use_edges()) { 841 for (Edge edge : node->use_edges()) {
662 if (NodeProperties::IsEffectEdge(edge)) { 842 if (NodeProperties::IsEffectEdge(edge)) {
663 return false; 843 return false;
664 } 844 }
665 } 845 }
666 return true; 846 return true;
667 } 847 }
668 848
669 849
670 bool EscapeAnalysis::Process(Node* node) { 850 bool EscapeAnalysis::Process(Node* node) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
733 } 913 }
734 break; 914 break;
735 } 915 }
736 } 916 }
737 } 917 }
738 918
739 919
740 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) { 920 bool EscapeAnalysis::IsEffectBranchPoint(Node* node) {
741 int count = 0; 921 int count = 0;
742 for (Edge edge : node->use_edges()) { 922 for (Edge edge : node->use_edges()) {
743 Node* use = edge.from(); 923 if (NodeProperties::IsEffectEdge(edge)) {
744 if (NodeProperties::IsEffectEdge(edge) &&
745 use->opcode() != IrOpcode::kLoadField) {
746 if (++count > 1) { 924 if (++count > 1) {
747 return true; 925 return true;
748 } 926 }
749 } 927 }
750 } 928 }
751 return false; 929 return false;
752 } 930 }
753 931
754 932
755 void EscapeAnalysis::ForwardVirtualState(Node* node) { 933 void EscapeAnalysis::ForwardVirtualState(Node* node) {
756 DCHECK_EQ(node->op()->EffectInputCount(), 1); 934 DCHECK_EQ(node->op()->EffectInputCount(), 1);
757 if (node->opcode() != IrOpcode::kLoadField && 935 if (node->opcode() != IrOpcode::kLoadField &&
758 node->opcode() != IrOpcode::kLoadElement && 936 node->opcode() != IrOpcode::kLoadElement &&
759 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { 937 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) {
760 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), 938 PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
761 node->op()->mnemonic()); 939 node->op()->mnemonic());
762 UNREACHABLE(); 940 UNREACHABLE();
763 } 941 }
764 Node* effect = NodeProperties::GetEffectInput(node); 942 Node* effect = NodeProperties::GetEffectInput(node);
765 // Break the cycle for effect phis. 943 // Break the cycle for effect phis.
766 if (effect->opcode() == IrOpcode::kEffectPhi) { 944 if (effect->opcode() == IrOpcode::kEffectPhi) {
767 if (virtual_states_[effect->id()] == nullptr) { 945 if (virtual_states_[effect->id()] == nullptr) {
768 virtual_states_[effect->id()] = 946 virtual_states_[effect->id()] =
769 new (zone()) VirtualState(zone(), graph()->NodeCount()); 947 new (zone()) VirtualState(zone(), graph()->NodeCount());
770 } 948 }
771 } 949 }
772 DCHECK_NOT_NULL(virtual_states_[effect->id()]); 950 DCHECK_NOT_NULL(virtual_states_[effect->id()]);
773 if (IsEffectBranchPoint(effect)) { 951 if (IsEffectBranchPoint(effect)) {
952 if (FLAG_trace_turbo_escape) {
953 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
954 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
955 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
956 }
774 if (!virtual_states_[node->id()]) { 957 if (!virtual_states_[node->id()]) {
775 virtual_states_[node->id()] = 958 virtual_states_[node->id()] =
776 new (zone()) VirtualState(*virtual_states_[effect->id()]); 959 new (zone()) VirtualState(*virtual_states_[effect->id()]);
777 } else { 960 } else {
778 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], 961 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()],
779 zone()); 962 zone());
780 } 963 }
781 if (FLAG_trace_turbo_escape) {
782 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
783 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
784 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
785 }
786 } else { 964 } else {
787 virtual_states_[node->id()] = virtual_states_[effect->id()]; 965 virtual_states_[node->id()] = virtual_states_[effect->id()];
788 if (FLAG_trace_turbo_escape) { 966 if (FLAG_trace_turbo_escape) {
789 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", 967 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n",
790 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), 968 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
791 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); 969 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
792 } 970 }
793 } 971 }
794 } 972 }
795 973
796 974
797 void EscapeAnalysis::ProcessStart(Node* node) { 975 void EscapeAnalysis::ProcessStart(Node* node) {
798 DCHECK_EQ(node->opcode(), IrOpcode::kStart); 976 DCHECK_EQ(node->opcode(), IrOpcode::kStart);
799 virtual_states_[node->id()] = 977 virtual_states_[node->id()] =
800 new (zone()) VirtualState(zone(), graph()->NodeCount()); 978 new (zone()) VirtualState(zone(), graph()->NodeCount());
801 } 979 }
802 980
803 981
804 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { 982 bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
805 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); 983 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
806 // For now only support binary phis.
807 CHECK_EQ(node->op()->EffectInputCount(), 2);
808 Node* left = NodeProperties::GetEffectInput(node, 0);
809 Node* right = NodeProperties::GetEffectInput(node, 1);
810 bool changed = false; 984 bool changed = false;
811 985
812 VirtualState* mergeState = virtual_states_[node->id()]; 986 VirtualState* mergeState = virtual_states_[node->id()];
813 if (!mergeState) { 987 if (!mergeState) {
814 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); 988 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount());
815 virtual_states_[node->id()] = mergeState; 989 virtual_states_[node->id()] = mergeState;
816 changed = true; 990 changed = true;
817 if (FLAG_trace_turbo_escape) { 991 if (FLAG_trace_turbo_escape) {
818 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), 992 PrintF("Effect Phi #%d got new states map %p.\n", node->id(),
819 static_cast<void*>(mergeState)); 993 static_cast<void*>(mergeState));
820 } 994 }
821 } else if (mergeState->GetLastChanged() != node) { 995 } else if (mergeState->GetLastChanged() != node) {
822 changed = true; 996 changed = true;
823 } 997 }
824 998
825 VirtualState* l = virtual_states_[left->id()]; 999 cache_.Clear();
826 VirtualState* r = virtual_states_[right->id()];
827 1000
828 if (l == nullptr && r == nullptr) { 1001 if (FLAG_trace_turbo_escape) {
1002 PrintF("At Effect Phi #%d, merging states into %p:", node->id(),
1003 static_cast<void*>(mergeState));
1004 }
1005
1006 for (int i = 0; i < node->op()->EffectInputCount(); ++i) {
1007 Node* input = NodeProperties::GetEffectInput(node, i);
1008 VirtualState* state = virtual_states_[input->id()];
1009 if (state) {
1010 cache_.states().push_back(state);
1011 }
1012 if (FLAG_trace_turbo_escape) {
1013 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(),
1014 input->op()->mnemonic());
1015 }
1016 }
1017 if (FLAG_trace_turbo_escape) {
1018 PrintF("\n");
1019 }
1020
1021 if (cache_.states().size() == 0) {
829 return changed; 1022 return changed;
830 } 1023 }
831 1024
832 if (FLAG_trace_turbo_escape) { 1025 changed = mergeState->MergeFrom(&cache_, zone(), graph(), common(),
833 PrintF( 1026 NodeProperties::GetControlInput(node)) ||
834 "At Effect Phi #%d, merging states %p (from #%d) and %p (from #%d) " 1027 changed;
835 "into %p\n",
836 node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r),
837 right->id(), static_cast<void*>(mergeState));
838 }
839 1028
840 if (r && l == nullptr) {
841 changed = mergeState->UpdateFrom(r, zone()) || changed;
842 } else if (l && r == nullptr) {
843 changed = mergeState->UpdateFrom(l, zone()) || changed;
844 } else {
845 changed = mergeState->MergeFrom(l, r, zone(), graph(), common(),
846 NodeProperties::GetControlInput(node)) ||
847 changed;
848 }
849 if (FLAG_trace_turbo_escape) { 1029 if (FLAG_trace_turbo_escape) {
850 PrintF("Merge %s the node.\n", changed ? "changed" : "did not change"); 1030 PrintF("Merge %s the node.\n", changed ? "changed" : "did not change");
851 } 1031 }
1032
852 if (changed) { 1033 if (changed) {
853 mergeState->LastChangedAt(node); 1034 mergeState->LastChangedAt(node);
854 } 1035 }
855 return changed; 1036 return changed;
856 } 1037 }
857 1038
858 1039
859 void EscapeAnalysis::ProcessAllocation(Node* node) { 1040 void EscapeAnalysis::ProcessAllocation(Node* node) {
860 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); 1041 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
861 ForwardVirtualState(node); 1042 ForwardVirtualState(node);
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
908 bool EscapeAnalysis::IsVirtual(Node* node) { 1089 bool EscapeAnalysis::IsVirtual(Node* node) {
909 return escape_status_.IsVirtual(node); 1090 return escape_status_.IsVirtual(node);
910 } 1091 }
911 1092
912 1093
913 bool EscapeAnalysis::IsEscaped(Node* node) { 1094 bool EscapeAnalysis::IsEscaped(Node* node) {
914 return escape_status_.IsEscaped(node); 1095 return escape_status_.IsEscaped(node);
915 } 1096 }
916 1097
917 1098
1099 bool EscapeAnalysis::SetEscaped(Node* node) {
1100 return escape_status_.SetEscaped(node);
1101 }
1102
1103
918 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { 1104 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
919 if (VirtualState* states = virtual_states_[at->id()]) { 1105 if (VirtualState* states = virtual_states_[at->id()]) {
920 return states->GetVirtualObject(id); 1106 return states->GetVirtualObject(id);
921 } 1107 }
922 return nullptr; 1108 return nullptr;
923 } 1109 }
924 1110
925 1111
926 int EscapeAnalysis::OffsetFromAccess(Node* node) { 1112 int EscapeAnalysis::OffsetFromAccess(Node* node) {
927 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); 1113 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
928 return OpParameter<FieldAccess>(node).offset / kPointerSize; 1114 return OpParameter<FieldAccess>(node).offset / kPointerSize;
929 } 1115 }
930 1116
931 1117
932 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, 1118 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node,
933 VirtualState* state) { 1119 VirtualState* state) {
934 // Only binary phis are supported for now.
935 CHECK_EQ(from->op()->ValueInputCount(), 2);
936 if (FLAG_trace_turbo_escape) { 1120 if (FLAG_trace_turbo_escape) {
937 PrintF("Load #%d from phi #%d", node->id(), from->id()); 1121 PrintF("Load #%d from phi #%d", node->id(), from->id());
938 } 1122 }
939 Node* left = NodeProperties::GetValueInput(from, 0); 1123
940 Node* right = NodeProperties::GetValueInput(from, 1); 1124 ZoneVector<Node*> inputs(zone());
941 VirtualObject* l = state->GetVirtualObject(left); 1125 for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
942 VirtualObject* r = state->GetVirtualObject(right); 1126 Node* input = NodeProperties::GetValueInput(node, i);
943 if (l && r) { 1127 inputs.push_back(input);
944 Node* lv = l->GetField(offset); 1128 }
945 Node* rv = r->GetField(offset); 1129
946 if (lv && rv) { 1130 GetVirtualObjects(state, inputs, cache_.objects());
1131 if (cache_.objects().size() == inputs.size()) {
1132 GetFields(cache_.objects(), cache_.fields(), offset);
1133 if (cache_.fields().size() == cache_.objects().size()) {
947 if (!state->GetVirtualObject(node)) { 1134 if (!state->GetVirtualObject(node)) {
948 state->SetVirtualObject(node->id(), 1135 state->SetVirtualObject(node->id(),
949 new (zone()) VirtualObject(node->id(), zone())); 1136 new (zone()) VirtualObject(node->id(), zone()));
950 } 1137 }
951 Node* rep = state->GetVirtualObject(node)->GetReplacement(); 1138 Node* rep = state->GetVirtualObject(node)->GetReplacement();
952 if (!rep || rep->opcode() != IrOpcode::kPhi || 1139 if (!rep || !IsEquivalentPhi(rep, cache_.fields())) {
953 NodeProperties::GetValueInput(rep, 0) != lv || 1140 cache_.fields().push_back(NodeProperties::GetControlInput(from));
954 NodeProperties::GetValueInput(rep, 1) != rv) { 1141 Node* phi = graph()->NewNode(
955 Node* phi = 1142 common()->Phi(MachineRepresentation::kTagged, 2),
956 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), 1143 static_cast<int>(cache_.fields().size()), &cache_.fields().front());
957 lv, rv, NodeProperties::GetControlInput(from));
958 state->GetVirtualObject(node)->SetReplacement(phi); 1144 state->GetVirtualObject(node)->SetReplacement(phi);
959 state->LastChangedAt(node); 1145 state->LastChangedAt(node);
960 if (FLAG_trace_turbo_escape) { 1146 if (FLAG_trace_turbo_escape) {
961 PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id()); 1147 PrintF(" got phi created.\n");
962 } 1148 }
963 } else if (FLAG_trace_turbo_escape) { 1149 } else if (FLAG_trace_turbo_escape) {
964 PrintF(" has already the right phi representation.\n"); 1150 PrintF(" has already phi #%d.\n", rep->id());
965 } 1151 }
966 } else if (FLAG_trace_turbo_escape) { 1152 } else if (FLAG_trace_turbo_escape) {
967 PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv), 1153 PrintF(" has incomplete field info.\n");
968 static_cast<void*>(rv));
969 } 1154 }
970 } else if (FLAG_trace_turbo_escape) { 1155 } else if (FLAG_trace_turbo_escape) {
971 PrintF(" has incomplete virtual object info: %p %p\n", 1156 PrintF(" has incomplete virtual object info.\n");
972 static_cast<void*>(l), static_cast<void*>(r));
973 } 1157 }
974 } 1158 }
975 1159
976 1160
977 void EscapeAnalysis::ProcessLoadField(Node* node) { 1161 void EscapeAnalysis::ProcessLoadField(Node* node) {
978 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); 1162 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField);
979 ForwardVirtualState(node); 1163 ForwardVirtualState(node);
980 Node* from = NodeProperties::GetValueInput(node, 0); 1164 Node* from = NodeProperties::GetValueInput(node, 0);
981 VirtualState* state = virtual_states_[node->id()]; 1165 VirtualState* state = virtual_states_[node->id()];
982 if (VirtualObject* object = state->ResolveVirtualObject(from)) { 1166 if (VirtualObject* object = state->ResolveVirtualObject(from)) {
983 int offset = OffsetFromAccess(node); 1167 int offset = OffsetFromAccess(node);
984 if (!object->IsTracked()) return; 1168 if (!object->IsTracked()) return;
985 Node* value = object->GetField(offset); 1169 Node* value = object->GetField(offset);
986 if (value) { 1170 if (value) {
987 value = state->ResolveReplacement(value); 1171 value = state->ResolveReplacement(value);
988 // Record that the load has this alias.
989 state->UpdateReplacement(node, value, zone());
990 } else if (FLAG_trace_turbo_escape) {
991 PrintF("No field %d on record for #%d\n", offset, from->id());
992 } 1172 }
1173 // Record that the load has this alias.
1174 state->UpdateReplacement(node, value, zone());
993 } else { 1175 } else {
994 if (from->opcode() == IrOpcode::kPhi) { 1176 if (from->opcode() == IrOpcode::kPhi) {
995 int offset = OffsetFromAccess(node); 1177 int offset = OffsetFromAccess(node);
996 // Only binary phis are supported for now. 1178 // Only binary phis are supported for now.
997 ProcessLoadFromPhi(offset, from, node, state); 1179 ProcessLoadFromPhi(offset, from, node, state);
998 } 1180 }
999 } 1181 }
1000 } 1182 }
1001 1183
1002 1184
1003 void EscapeAnalysis::ProcessLoadElement(Node* node) { 1185 void EscapeAnalysis::ProcessLoadElement(Node* node) {
1004 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); 1186 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement);
1005 ForwardVirtualState(node); 1187 ForwardVirtualState(node);
1006 Node* from = NodeProperties::GetValueInput(node, 0); 1188 Node* from = NodeProperties::GetValueInput(node, 0);
1007 VirtualState* state = virtual_states_[node->id()]; 1189 VirtualState* state = virtual_states_[node->id()];
1008 if (VirtualObject* object = state->ResolveVirtualObject(from)) { 1190 Node* index_node = node->InputAt(1);
1009 NumberMatcher index(node->InputAt(1)); 1191 NumberMatcher index(index_node);
1010 ElementAccess access = OpParameter<ElementAccess>(node); 1192 ElementAccess access = OpParameter<ElementAccess>(node);
1011 if (index.HasValue()) { 1193 if (index.HasValue()) {
1012 CHECK_EQ(ElementSizeLog2Of(access.machine_type.representation()), 1194 int offset = index.Value() + access.header_size / kPointerSize;
1195 if (VirtualObject* object = state->ResolveVirtualObject(from)) {
1196 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
1013 kPointerSizeLog2); 1197 kPointerSizeLog2);
1014 CHECK_EQ(access.header_size % kPointerSize, 0); 1198 CHECK_EQ(access.header_size % kPointerSize, 0);
1015 int offset = index.Value() + access.header_size / kPointerSize; 1199
1016 if (!object->IsTracked()) return; 1200 if (!object->IsTracked()) return;
1017 Node* value = object->GetField(offset); 1201 Node* value = object->GetField(offset);
1018 if (value) { 1202 if (value) {
1019 value = state->ResolveReplacement(value); 1203 value = state->ResolveReplacement(value);
1020 // Record that the load has this alias.
1021 state->UpdateReplacement(node, value, zone());
1022 } else if (FLAG_trace_turbo_escape) {
1023 PrintF("No field %d on record for #%d\n", offset, from->id());
1024 } 1204 }
1205 // Record that the load has this alias.
1206 state->UpdateReplacement(node, value, zone());
1207 } else if (from->opcode() == IrOpcode::kPhi) {
1208 ElementAccess access = OpParameter<ElementAccess>(node);
1209 int offset = index.Value() + access.header_size / kPointerSize;
1210 ProcessLoadFromPhi(offset, from, node, state);
1025 } 1211 }
1026 } else { 1212 } else {
1027 if (from->opcode() == IrOpcode::kPhi) { 1213 // We have a load from a non-const index, cannot eliminate object.
1028 NumberMatcher index(node->InputAt(1)); 1214 if (SetEscaped(from)) {
1029 ElementAccess access = OpParameter<ElementAccess>(node); 1215 if (FLAG_trace_turbo_escape) {
1030 int offset = index.Value() + access.header_size / kPointerSize; 1216 PrintF(
1031 if (index.HasValue()) { 1217 "Setting #%d (%s) to escaped because store element #%d to "
1032 ProcessLoadFromPhi(offset, from, node, state); 1218 "non-const "
1219 "index #%d (%s)\n",
1220 from->id(), from->op()->mnemonic(), node->id(), index_node->id(),
1221 index_node->op()->mnemonic());
1033 } 1222 }
1034 } 1223 }
1035 } 1224 }
1036 } 1225 }
1037 1226
1038 1227
1039 void EscapeAnalysis::ProcessStoreField(Node* node) { 1228 void EscapeAnalysis::ProcessStoreField(Node* node) {
1040 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); 1229 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
1041 ForwardVirtualState(node); 1230 ForwardVirtualState(node);
1042 Node* to = NodeProperties::GetValueInput(node, 0); 1231 Node* to = NodeProperties::GetValueInput(node, 0);
1043 Node* val = NodeProperties::GetValueInput(node, 1); 1232 Node* val = NodeProperties::GetValueInput(node, 1);
1044 int offset = OffsetFromAccess(node); 1233 int offset = OffsetFromAccess(node);
1045 VirtualState* states = virtual_states_[node->id()]; 1234 VirtualState* states = virtual_states_[node->id()];
1046 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { 1235 if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
1047 if (!obj->IsTracked()) return; 1236 if (!obj->IsTracked()) return;
1048 if (obj->SetField(offset, states->ResolveReplacement(val))) { 1237 if (obj->SetField(offset, states->ResolveReplacement(val))) {
1049 states->LastChangedAt(node); 1238 states->LastChangedAt(node);
1050 } 1239 }
1051 } 1240 }
1052 } 1241 }
1053 1242
1054 1243
1055 void EscapeAnalysis::ProcessStoreElement(Node* node) { 1244 void EscapeAnalysis::ProcessStoreElement(Node* node) {
1056 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); 1245 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
1057 ForwardVirtualState(node); 1246 ForwardVirtualState(node);
1058 Node* to = NodeProperties::GetValueInput(node, 0); 1247 Node* to = NodeProperties::GetValueInput(node, 0);
1059 NumberMatcher index(node->InputAt(1)); 1248 Node* index_node = node->InputAt(1);
1249 NumberMatcher index(index_node);
1060 ElementAccess access = OpParameter<ElementAccess>(node); 1250 ElementAccess access = OpParameter<ElementAccess>(node);
1061 Node* val = NodeProperties::GetValueInput(node, 2); 1251 Node* val = NodeProperties::GetValueInput(node, 2);
1062 if (index.HasValue()) { 1252 if (index.HasValue()) {
1063 CHECK_EQ(ElementSizeLog2Of(access.machine_type.representation()),
1064 kPointerSizeLog2);
1065 CHECK_EQ(access.header_size % kPointerSize, 0);
1066 int offset = index.Value() + access.header_size / kPointerSize; 1253 int offset = index.Value() + access.header_size / kPointerSize;
1067 VirtualState* states = virtual_states_[node->id()]; 1254 VirtualState* states = virtual_states_[node->id()];
1068 if (VirtualObject* obj = states->ResolveVirtualObject(to)) { 1255 if (VirtualObject* obj = states->ResolveVirtualObject(to)) {
1069 if (!obj->IsTracked()) return; 1256 if (!obj->IsTracked()) return;
1257 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
1258 kPointerSizeLog2);
1259 CHECK_EQ(access.header_size % kPointerSize, 0);
1070 if (obj->SetField(offset, states->ResolveReplacement(val))) { 1260 if (obj->SetField(offset, states->ResolveReplacement(val))) {
1071 states->LastChangedAt(node); 1261 states->LastChangedAt(node);
1072 } 1262 }
1073 } 1263 }
1264 } else {
1265 // We have a store to a non-const index, cannot eliminate object.
1266 if (SetEscaped(to)) {
1267 if (FLAG_trace_turbo_escape) {
1268 PrintF(
1269 "Setting #%d (%s) to escaped because store element #%d to "
1270 "non-const "
1271 "index #%d (%s)\n",
1272 to->id(), to->op()->mnemonic(), node->id(), index_node->id(),
1273 index_node->op()->mnemonic());
1274 }
1275 }
1074 } 1276 }
1075 } 1277 }
1076 1278
1077 1279
1078 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { 1280 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) {
1079 PrintF(" Object #%d with %zu fields", id, object->field_count()); 1281 PrintF(" Object #%d with %zu fields", id, object->field_count());
1080 if (Node* rep = object->GetReplacement()) { 1282 if (Node* rep = object->GetReplacement()) {
1081 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); 1283 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic());
1082 } 1284 }
1083 PrintF("\n"); 1285 PrintF("\n");
(...skipping 30 matching lines...) Expand all
1114 } 1316 }
1115 } 1317 }
1116 for (size_t n = 0; n < object_states.size(); n++) { 1318 for (size_t n = 0; n < object_states.size(); n++) {
1117 DebugPrintState(object_states[n]); 1319 DebugPrintState(object_states[n]);
1118 } 1320 }
1119 } 1321 }
1120 1322
1121 } // namespace compiler 1323 } // namespace compiler
1122 } // namespace internal 1324 } // namespace internal
1123 } // namespace v8 1325 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698