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

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

Issue 1457683003: [turbofan] Initial support for escape analysis. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "src/compiler/escape-analysis.h"
6
7 #include "src/base/flags.h"
8 #include "src/bootstrapper.h"
9 #include "src/compilation-dependencies.h"
10 #include "src/compiler/common-operator.h"
11 #include "src/compiler/graph-reducer.h"
12 #include "src/compiler/js-operator.h"
13 #include "src/compiler/node.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/simplified-operator.h"
17 #include "src/objects-inl.h"
18 #include "src/type-cache.h"
19
20 namespace v8 {
21 namespace internal {
22 namespace compiler {
23
24
25 class VirtualObject : public ZoneObject {
26 public:
27 enum Status { kUntracked = 0, kTracked = 1 };
28 VirtualObject(NodeId id, Zone* zone)
29 : id_(id), status_(kUntracked), fields_(zone), replacement_(nullptr) {}
30
31 VirtualObject(const VirtualObject& other)
32 : id_(other.id_),
33 status_(other.status_),
34 fields_(other.fields_),
35 replacement_(other.replacement_) {}
36
37 VirtualObject(NodeId id, Zone* zone, size_t field_number)
38 : id_(id), status_(kTracked), fields_(zone), replacement_(nullptr) {
39 fields_.resize(field_number);
40 }
41
42 Node* GetField(size_t offset) {
43 if (offset < fields_.size()) {
44 return fields_[offset];
45 }
46 return nullptr;
47 }
48
49 bool SetField(size_t offset, Node* node) {
50 bool changed = fields_[offset] != node;
51 fields_[offset] = node;
52 return changed;
53 }
54 bool IsVirtual() const { return status_ == kTracked; }
55 bool IsTracked() const { return status_ != kUntracked; }
56 Node* GetReplacement() { return replacement_; }
57 bool SetReplacement(Node* node) {
58 bool changed = replacement_ != node;
59 replacement_ = node;
60 return changed;
61 }
62
63 size_t fields() { return fields_.size(); }
64 bool ResizeFields(size_t field_number) {
65 if (field_number != fields_.size()) {
66 fields_.resize(field_number);
67 return true;
68 }
69 return false;
70 }
71
72 bool UpdateFrom(const VirtualObject& other);
73
74 NodeId id() { return id_; }
75 void id(NodeId id) { id_ = id; }
76
77 private:
78 NodeId id_;
79 Status status_;
80 ZoneVector<Node*> fields_;
81 Node* replacement_;
82 };
83
84
85 class VirtualState : public ZoneObject {
86 public:
87 VirtualState(Zone* zone, size_t size);
88 VirtualState(const VirtualState& states);
89
90 VirtualObject* GetVirtualObject(Node* node);
91 VirtualObject* GetVirtualObject(size_t id);
92 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone);
93 void SetVirtualObject(NodeId id, VirtualObject* state);
94 void LastChangedAt(Node* node) { last_changed_ = node; }
95 Node* GetLastChanged() { return last_changed_; }
96 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone);
97 Node* ResolveReplacement(Node* node);
98 bool UpdateReplacement(Node* node, Node* rep, Zone* zone);
99 bool UpdateFrom(VirtualState* state, Zone* zone);
100 bool MergeFrom(VirtualState* left, VirtualState* right, Zone* zone,
101 Graph* graph, CommonOperatorBuilder* common, Node* control);
102
103 size_t size() { return info_.size(); }
104
105 private:
106 ZoneVector<VirtualObject*> info_;
107 Node* last_changed_;
108 };
109
110
111 bool VirtualObject::UpdateFrom(const VirtualObject& other) {
112 bool changed = status_ != other.status_;
113 status_ = other.status_;
114 changed = replacement_ != other.replacement_ || changed;
115 replacement_ = other.replacement_;
116 if (fields_.size() != other.fields_.size()) {
117 fields_ = other.fields_;
118 return true;
119 }
120 for (size_t i = 0; i < fields_.size(); ++i) {
121 if (fields_[i] != other.fields_[i]) {
122 changed = true;
123 fields_[i] = other.fields_[i];
124 }
125 }
126 return changed;
127 }
128
129
130 VirtualState::VirtualState(Zone* zone, size_t size)
131 : info_(zone), last_changed_(nullptr) {
132 info_.resize(size);
133 }
134
135
136 VirtualState::VirtualState(const VirtualState& state)
137 : info_(state.info_.get_allocator().zone()),
138 last_changed_(state.last_changed_) {
139 info_.resize(state.info_.size());
140 for (size_t i = 0; i < state.info_.size(); ++i) {
141 if (state.info_[i] && state.info_[i]->id() == i) {
142 info_[i] = new (state.info_.get_allocator().zone())
143 VirtualObject(*state.info_[i]);
144 }
145 }
146 for (size_t i = 0; i < state.info_.size(); ++i) {
147 if (state.info_[i] && state.info_[i]->id() != i) {
148 info_[i] = info_[state.info_[i]->id()];
149 }
150 }
151 }
152
153
154 VirtualObject* VirtualState::GetVirtualObject(size_t id) { return info_[id]; }
155
156
157 VirtualObject* VirtualState::GetVirtualObject(Node* node) {
158 return GetVirtualObject(node->id());
159 }
160
161
162 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id,
163 Zone* zone) {
164 if (VirtualObject* obj = GetVirtualObject(id)) {
165 return obj;
166 }
167 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0);
168 SetVirtualObject(id, obj);
169 return obj;
170 }
171
172
173 void VirtualState::SetVirtualObject(NodeId id, VirtualObject* obj) {
174 info_[id] = obj;
175 }
176
177
178 bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) {
179 VirtualObject* obj = GetVirtualObject(id);
180 if (!obj) {
181 obj = new (zone) VirtualObject(*fromObj);
182 SetVirtualObject(id, obj);
183 if (FLAG_trace_turbo_escape) {
184 PrintF(" Taking field for #%d from %p\n", id,
185 static_cast<void*>(fromObj));
186 }
187 return true;
188 }
189
190 if (obj->UpdateFrom(*fromObj)) {
191 if (FLAG_trace_turbo_escape) {
192 PrintF(" Updating field for #%d from %p\n", id,
193 static_cast<void*>(fromObj));
194 }
195 return true;
196 }
197
198 return false;
199 }
200
201
202 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
203 DCHECK_EQ(size(), from->size());
204 bool changed = false;
205 for (NodeId id = 0; id < size(); ++id) {
206 VirtualObject* ls = GetVirtualObject(id);
207 VirtualObject* rs = from->GetVirtualObject(id);
208
209 if (rs == nullptr) {
210 continue;
211 }
212
213 if (ls == nullptr) {
214 ls = new (zone) VirtualObject(*rs);
215 SetVirtualObject(id, ls);
216 changed = true;
217 continue;
218 }
219
220 if (FLAG_trace_turbo_escape) {
221 PrintF(" Updating fields of #%d\n", id);
222 }
223
224 changed = ls->UpdateFrom(*rs) || changed;
225 }
226 return false;
227 }
228
229
230 bool VirtualState::MergeFrom(VirtualState* left, VirtualState* right,
231 Zone* zone, Graph* graph,
232 CommonOperatorBuilder* common, Node* control) {
233 bool changed = false;
234 for (NodeId id = 0; id < std::min(left->size(), right->size()); ++id) {
235 VirtualObject* ls = left->GetVirtualObject(id);
236 VirtualObject* rs = right->GetVirtualObject(id);
237
238 if (ls != nullptr && rs != nullptr) {
239 if (FLAG_trace_turbo_escape) {
240 PrintF(" Merging fields of #%d\n", id);
241 }
242 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone);
243 size_t fields = std::max(ls->fields(), rs->fields());
244 changed = mergeObject->ResizeFields(fields) || changed;
245 for (size_t i = 0; i < fields; ++i) {
246 if (ls->GetField(i) == rs->GetField(i)) {
247 changed = mergeObject->SetField(i, ls->GetField(i)) || changed;
248 if (FLAG_trace_turbo_escape && ls->GetField(i)) {
249 PrintF(" Field %zu agree on rep #%d\n", i,
250 ls->GetField(i)->id());
251 }
252 } else if (ls->GetField(i) != nullptr && rs->GetField(i) != nullptr) {
253 Node* phi = graph->NewNode(common->Phi(kMachAnyTagged, 2),
254 ls->GetField(i), rs->GetField(i), control);
255 if (mergeObject->SetField(i, phi)) {
256 if (FLAG_trace_turbo_escape) {
257 PrintF(" Creating Phi #%d as merge of #%d and #%d\n",
258 phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id());
259 }
260 changed = true;
261 }
262 } else {
263 changed = mergeObject->SetField(i, nullptr) || changed;
264 }
265 }
266 }
267 }
268 return changed;
269 }
270
271
272 Node* VirtualState::ResolveReplacement(Node* node) {
273 if (VirtualObject* obj = GetVirtualObject(node)) {
274 if (Node* rep = obj->GetReplacement()) {
275 return rep;
276 }
277 }
278 return node;
279 }
280
281
282 bool VirtualState::UpdateReplacement(Node* node, Node* rep, Zone* zone) {
283 if (!GetVirtualObject(node)) {
284 SetVirtualObject(node->id(), new (zone) VirtualObject(node->id(), zone));
285 }
286 if (GetVirtualObject(node)->SetReplacement(rep)) {
287 LastChangedAt(node);
288 if (FLAG_trace_turbo_escape) {
289 PrintF("Representation of #%d is #%d (%s)\n", node->id(), rep->id(),
290 rep->op()->mnemonic());
291 }
292 return true;
293 }
294 return false;
295 }
296
297
298 // ------------------------------EscapeStatusAnalysis---------------------------
299
300
301 EscapeStatusAnalysis::EscapeStatusAnalysis(
302 EscapeObjectAnalysis* object_analysis, Graph* graph, Zone* zone)
303 : object_analysis_(object_analysis),
304 graph_(graph),
305 zone_(zone),
306 info_(zone),
307 queue_(zone) {}
308
309
310 EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
311
312
313 bool EscapeStatusAnalysis::HasEntry(Node* node) {
314 return info_[node->id()] != kUnknown;
315 }
316
317
318 bool EscapeStatusAnalysis::IsVirtual(Node* node) {
319 if (node->id() >= info_.size()) {
320 return false;
321 }
322 return info_[node->id()] == kVirtual;
323 }
324
325
326 bool EscapeStatusAnalysis::IsEscaped(Node* node) {
327 return info_[node->id()] == kEscaped;
328 }
329
330
331 bool EscapeStatusAnalysis::SetEscaped(Node* node) {
332 bool changed = info_[node->id()] != kEscaped;
333 info_[node->id()] = kEscaped;
334 return changed;
335 }
336
337
338 void EscapeStatusAnalysis::Run() {
339 info_.resize(graph()->NodeCount());
340 ZoneVector<bool> visited(zone());
341 visited.resize(graph()->NodeCount());
342 queue_.push_back(graph()->end());
343 while (!queue_.empty()) {
344 Node* node = queue_.front();
345 queue_.pop_front();
346 Process(node);
347 if (!visited[node->id()]) {
348 RevisitInputs(node);
349 }
350 visited[node->id()] = true;
351 }
352 if (FLAG_trace_turbo_escape) {
353 DebugPrint();
354 }
355 }
356
357
358 void EscapeStatusAnalysis::RevisitInputs(Node* node) {
359 for (Edge edge : node->input_edges()) {
360 Node* input = edge.to();
361 queue_.push_back(input);
362 }
363 }
364
365
366 void EscapeStatusAnalysis::RevisitUses(Node* node) {
367 for (Edge edge : node->use_edges()) {
368 Node* use = edge.from();
369 queue_.push_back(use);
370 }
371 }
372
373
374 void EscapeStatusAnalysis::Process(Node* node) {
375 switch (node->opcode()) {
376 case IrOpcode::kAllocate:
377 ProcessAllocate(node);
378 break;
379 case IrOpcode::kFinishRegion:
380 ProcessFinishRegion(node);
381 break;
382 case IrOpcode::kStoreField:
383 ProcessStoreField(node);
384 break;
385 case IrOpcode::kLoadField: {
386 if (Node* rep = object_analysis_->GetReplacement(node, node->id())) {
387 if (rep->opcode() == IrOpcode::kAllocate ||
388 rep->opcode() == IrOpcode::kFinishRegion) {
389 if (CheckUsesForEscape(node, rep)) {
390 RevisitInputs(rep);
391 RevisitUses(rep);
392 }
393 }
394 }
395 break;
396 }
397 case IrOpcode::kPhi:
398 if (!HasEntry(node)) {
399 info_[node->id()] = kVirtual;
400 }
401 CheckUsesForEscape(node);
402 default:
403 break;
404 }
405 }
406
407
408 void EscapeStatusAnalysis::ProcessStoreField(Node* node) {
409 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
410 Node* to = NodeProperties::GetValueInput(node, 0);
411 Node* val = NodeProperties::GetValueInput(node, 1);
412 if (IsEscaped(to) && SetEscaped(val)) {
413 RevisitUses(val);
414 if (FLAG_trace_turbo_escape) {
415 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
416 val->id(), val->op()->mnemonic(), to->id());
417 }
418 }
419 }
420
421
422 void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
423 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
424 if (!HasEntry(node)) {
425 info_[node->id()] = kVirtual;
426 if (FLAG_trace_turbo_escape) {
427 PrintF("Created status entry for node #%d (%s)\n", node->id(),
428 node->op()->mnemonic());
429 }
430 NumberMatcher size(node->InputAt(0));
431 if (!size.HasValue() && SetEscaped(node)) {
432 RevisitUses(node);
433 if (FLAG_trace_turbo_escape) {
434 PrintF("Setting #%d to escaped because of non-const alloc\n",
435 node->id());
436 }
437 // This node is known to escape, uses do not have to be checked.
438 return;
439 }
440 }
441 if (CheckUsesForEscape(node)) {
442 RevisitUses(node);
443 }
444 }
445
446
447 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep) {
448 for (Edge edge : uses->use_edges()) {
449 Node* use = edge.from();
450 if (!NodeProperties::IsValueEdge(edge)) continue;
451 switch (use->opcode()) {
452 case IrOpcode::kStoreField:
453 case IrOpcode::kLoadField:
454 case IrOpcode::kFrameState:
455 case IrOpcode::kStateValues:
456 case IrOpcode::kReferenceEqual:
457 case IrOpcode::kFinishRegion:
458 case IrOpcode::kPhi:
459 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) {
460 if (FLAG_trace_turbo_escape) {
461 PrintF(
462 "Setting #%d (%s) to escaped because of use by escaping node "
463 "#%d (%s)\n",
464 rep->id(), rep->op()->mnemonic(), use->id(),
465 use->op()->mnemonic());
466 }
467 return true;
468 }
469 break;
470 default:
471 if (SetEscaped(rep)) {
472 if (FLAG_trace_turbo_escape) {
473 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
474 rep->id(), rep->op()->mnemonic(), use->id(),
475 use->op()->mnemonic());
476 }
477 return true;
478 }
479 if (use->op()->EffectInputCount() == 0 &&
480 uses->op()->EffectInputCount() > 0 &&
481 uses->opcode() != IrOpcode::kLoadField) {
482 if (FLAG_trace_turbo_escape) {
483 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(),
484 use->op()->mnemonic());
485 }
486 UNREACHABLE();
487 }
488 }
489 }
490 return false;
491 }
492
493
494 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
495 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
496 if (!HasEntry(node)) {
497 info_[node->id()] = kVirtual;
498 RevisitUses(node);
499 }
500 if (CheckUsesForEscape(node)) {
501 RevisitInputs(node);
502 }
503 }
504
505
506 void EscapeStatusAnalysis::DebugPrint() {
507 for (NodeId id = 0; id < info_.size(); id++) {
508 if (info_[id] != kUnknown) {
509 PrintF("Node #%d is %s\n", id,
510 info_[id] == kEscaped ? "escaping" : "virtual");
511 }
512 }
513 }
514
515
516 // -----------------------------EscapeObjectAnalysis---------------------------
517
518
519 EscapeObjectAnalysis::EscapeObjectAnalysis(Graph* graph,
520 CommonOperatorBuilder* common,
521 Zone* zone)
522 : graph_(graph), common_(common), zone_(zone), virtual_states_(zone) {}
523
524
525 EscapeObjectAnalysis::~EscapeObjectAnalysis() {}
526
527
528 void EscapeObjectAnalysis::Run() {
529 virtual_states_.resize(graph()->NodeCount());
530 ZoneVector<Node*> queue(zone());
531 queue.push_back(graph()->start());
532 while (!queue.empty()) {
533 Node* node = queue.back();
534 queue.pop_back();
535 if (Process(node)) {
536 for (Edge edge : node->use_edges()) {
537 if (NodeProperties::IsEffectEdge(edge)) {
538 Node* use = edge.from();
539 if (use->opcode() != IrOpcode::kLoadField ||
540 !IsDanglingEffectNode(use)) {
541 queue.push_back(use);
542 }
543 }
544 }
545 // First process loads: dangling loads are a problem otherwise.
546 for (Edge edge : node->use_edges()) {
547 if (NodeProperties::IsEffectEdge(edge)) {
548 Node* use = edge.from();
549 if (use->opcode() == IrOpcode::kLoadField &&
550 IsDanglingEffectNode(use)) {
551 queue.push_back(use);
552 }
553 }
554 }
555 }
556 }
557 if (FLAG_trace_turbo_escape) {
558 DebugPrint();
559 }
560 }
561
562
563 bool EscapeObjectAnalysis::IsDanglingEffectNode(Node* node) {
564 if (node->op()->EffectInputCount() == 0) return false;
565 if (node->op()->EffectOutputCount() == 0) return false;
566 for (Edge edge : node->use_edges()) {
567 if (NodeProperties::IsEffectEdge(edge)) {
568 return false;
569 }
570 }
571 return true;
572 }
573
574
575 bool EscapeObjectAnalysis::Process(Node* node) {
576 switch (node->opcode()) {
577 case IrOpcode::kAllocate:
578 ProcessAllocation(node);
579 break;
580 case IrOpcode::kBeginRegion:
581 ForwardVirtualState(node);
582 break;
583 case IrOpcode::kFinishRegion:
584 ProcessFinishRegion(node);
585 break;
586 case IrOpcode::kStoreField:
587 ProcessStoreField(node);
588 break;
589 case IrOpcode::kLoadField:
590 ProcessLoadField(node);
591 break;
592 case IrOpcode::kStart:
593 ProcessStart(node);
594 break;
595 case IrOpcode::kEffectPhi:
596 return ProcessEffectPhi(node);
597 break;
598 default:
599 if (node->op()->EffectInputCount() > 0) {
600 ForwardVirtualState(node);
601 }
602 break;
603 }
604 return true;
605 }
606
607
608 bool EscapeObjectAnalysis::IsEffectBranchPoint(Node* node) {
609 int count = 0;
610 for (Edge edge : node->use_edges()) {
611 Node* use = edge.from();
612 if (NodeProperties::IsEffectEdge(edge) &&
613 use->opcode() != IrOpcode::kLoadField) {
614 if (++count > 1) {
615 return true;
616 }
617 }
618 }
619 return false;
620 }
621
622
623 void EscapeObjectAnalysis::ForwardVirtualState(Node* node) {
624 DCHECK_EQ(node->op()->EffectInputCount(), 1);
625 if (node->opcode() != IrOpcode::kLoadField && IsDanglingEffectNode(node)) {
626 PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
627 node->op()->mnemonic());
628 DCHECK(false);
629 }
630 Node* effect = NodeProperties::GetEffectInput(node);
631 // Break the cycle for effect phis.
632 if (effect->opcode() == IrOpcode::kEffectPhi) {
633 if (virtual_states_[effect->id()] == nullptr) {
634 virtual_states_[effect->id()] =
635 new (zone()) VirtualState(zone(), graph()->NodeCount());
636 }
637 }
638 DCHECK_NOT_NULL(virtual_states_[effect->id()]);
639 if (IsEffectBranchPoint(effect)) {
640 if (virtual_states_[node->id()]) return;
641 virtual_states_[node->id()] =
642 new (zone()) VirtualState(*virtual_states_[effect->id()]);
643 if (FLAG_trace_turbo_escape) {
644 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
645 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
646 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
647 }
648 } else {
649 virtual_states_[node->id()] = virtual_states_[effect->id()];
650 if (FLAG_trace_turbo_escape) {
651 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n",
652 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
653 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
654 }
655 }
656 }
657
658
659 void EscapeObjectAnalysis::ProcessStart(Node* node) {
660 DCHECK_EQ(node->opcode(), IrOpcode::kStart);
661 virtual_states_[node->id()] =
662 new (zone()) VirtualState(zone(), graph()->NodeCount());
663 }
664
665
666 bool EscapeObjectAnalysis::ProcessEffectPhi(Node* node) {
667 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
668 // For now only support binary phis.
669 DCHECK_EQ(node->op()->EffectInputCount(), 2);
670 Node* left = NodeProperties::GetEffectInput(node, 0);
671 Node* right = NodeProperties::GetEffectInput(node, 1);
672 bool changed = false;
673
674 VirtualState* mergeState = virtual_states_[node->id()];
675 if (!mergeState) {
676 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount());
677 virtual_states_[node->id()] = mergeState;
678 changed = true;
679 if (FLAG_trace_turbo_escape) {
680 PrintF("Phi #%d got new states map %p.\n", node->id(),
681 static_cast<void*>(mergeState));
682 }
683 } else if (mergeState->GetLastChanged() != node) {
684 changed = true;
685 }
686
687 VirtualState* l = virtual_states_[left->id()];
688 VirtualState* r = virtual_states_[right->id()];
689
690 if (l == nullptr && r == nullptr) {
691 return changed;
692 }
693
694 if (FLAG_trace_turbo_escape) {
695 PrintF("At Phi #%d, merging states %p (from #%d) and %p (from #%d)\n",
696 node->id(), static_cast<void*>(l), left->id(), static_cast<void*>(r),
697 right->id());
698 }
699
700 if (r && l == nullptr) {
701 changed = mergeState->UpdateFrom(r, zone()) || changed;
702 } else if (l && r == nullptr) {
703 changed = mergeState->UpdateFrom(l, zone()) || changed;
704 } else {
705 changed = mergeState->MergeFrom(l, r, zone(), graph(), common(),
706 NodeProperties::GetControlInput(node)) ||
707 changed;
708 }
709 if (FLAG_trace_turbo_escape) {
710 PrintF("Merge %s the node.\n", changed ? "changed" : "did not change");
711 }
712 if (changed) {
713 mergeState->LastChangedAt(node);
714 }
715 return changed;
716 }
717
718
719 void EscapeObjectAnalysis::ProcessAllocation(Node* node) {
720 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
721 ForwardVirtualState(node);
722
723 // Check if we have already processed this node.
724 if (virtual_states_[node->id()]->GetVirtualObject(node)) return;
725
726 NumberMatcher size(node->InputAt(0));
727 if (size.HasValue()) {
728 virtual_states_[node->id()]->SetVirtualObject(
729 node->id(), new (zone()) VirtualObject(node->id(), zone(),
730 size.Value() / kPointerSize));
731 } else {
732 virtual_states_[node->id()]->SetVirtualObject(
733 node->id(), new (zone()) VirtualObject(node->id(), zone()));
734 }
735 virtual_states_[node->id()]->LastChangedAt(node);
736 }
737
738
739 void EscapeObjectAnalysis::ProcessFinishRegion(Node* node) {
740 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
741 ForwardVirtualState(node);
742 Node* allocation = NodeProperties::GetValueInput(node, 0);
743 if (allocation->opcode() == IrOpcode::kAllocate) {
744 VirtualState* states = virtual_states_[node->id()];
745 DCHECK_NOT_NULL(states->GetVirtualObject(allocation));
746 if (!states->GetVirtualObject(node->id())) {
747 states->SetVirtualObject(node->id(),
748 states->GetVirtualObject(allocation));
749 if (FLAG_trace_turbo_escape) {
750 PrintF("Linked finish region node #%d to node #%d\n", node->id(),
751 allocation->id());
752 }
753 states->LastChangedAt(node);
754 }
755 }
756 }
757
758
759 Node* EscapeObjectAnalysis::GetReplacement(Node* at, NodeId id) {
760 VirtualState* states = virtual_states_[at->id()];
761 if (VirtualObject* obj = states->GetVirtualObject(id)) {
762 return obj->GetReplacement();
763 }
764 return nullptr;
765 }
766
767
768 int EscapeObjectAnalysis::OffsetFromAccess(Node* node) {
769 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
770 return OpParameter<FieldAccess>(node).offset / kPointerSize;
771 }
772
773
774 void EscapeObjectAnalysis::ProcessLoadField(Node* node) {
775 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField);
776 ForwardVirtualState(node);
777 Node* from = NodeProperties::GetValueInput(node, 0);
778 int offset = OffsetFromAccess(node);
779 VirtualState* states = virtual_states_[node->id()];
780 if (VirtualObject* state = states->GetVirtualObject(from)) {
781 if (!state->IsTracked()) return;
782 Node* value = state->GetField(offset);
783 if (value) {
784 // Record that the load has this alias.
785 states->UpdateReplacement(node, value, zone());
786 } else if (FLAG_trace_turbo_escape) {
787 PrintF("No field %d on record for #%d\n", offset, from->id());
788 }
789 } else {
790 if (from->opcode() == IrOpcode::kPhi) {
791 // Only binary phis are supported for now.
792 CHECK_EQ(from->op()->ValueInputCount(), 2);
793 if (FLAG_trace_turbo_escape) {
794 PrintF("Load #%d from phi #%d", node->id(), from->id());
795 }
796 Node* left = NodeProperties::GetValueInput(from, 0);
797 Node* right = NodeProperties::GetValueInput(from, 1);
798 VirtualObject* l = states->GetVirtualObject(left);
799 VirtualObject* r = states->GetVirtualObject(right);
800 if (l && r) {
801 Node* lv = l->GetField(offset);
802 Node* rv = r->GetField(offset);
803 if (lv && rv) {
804 if (!states->GetVirtualObject(node)) {
805 states->SetVirtualObject(
806 node->id(), new (zone()) VirtualObject(node->id(), zone()));
807 }
808 Node* rep = states->GetVirtualObject(node)->GetReplacement();
809 if (!rep || rep->opcode() != IrOpcode::kPhi ||
810 NodeProperties::GetValueInput(rep, 0) != lv ||
811 NodeProperties::GetValueInput(rep, 1) != rv) {
812 Node* phi =
813 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv,
814 NodeProperties::GetControlInput(from));
815 states->GetVirtualObject(node)->SetReplacement(phi);
816 states->LastChangedAt(node);
817 if (FLAG_trace_turbo_escape) {
818 PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id());
819 }
820 } else if (FLAG_trace_turbo_escape) {
821 PrintF(" has already the right phi representation.\n");
822 }
823 } else if (FLAG_trace_turbo_escape) {
824 PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv),
825 static_cast<void*>(rv));
826 }
827 } else if (FLAG_trace_turbo_escape) {
828 PrintF(" has incomplete virtual object info: %p %p\n",
829 static_cast<void*>(l), static_cast<void*>(r));
830 }
831 }
832 }
833 }
834
835
836 void EscapeObjectAnalysis::ProcessStoreField(Node* node) {
837 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
838 ForwardVirtualState(node);
839 Node* to = NodeProperties::GetValueInput(node, 0);
840 Node* val = NodeProperties::GetValueInput(node, 1);
841 int offset = OffsetFromAccess(node);
842 VirtualState* states = virtual_states_[node->id()];
843 if (VirtualObject* obj = states->GetVirtualObject(to)) {
844 if (!obj->IsTracked()) return;
845 if (obj->SetField(offset, states->ResolveReplacement(val))) {
846 states->LastChangedAt(node);
847 }
848 }
849 }
850
851
852 void EscapeObjectAnalysis::DebugPrint() {
853 ZoneVector<VirtualState*> object_states(zone());
854 for (NodeId id = 0; id < virtual_states_.size(); id++) {
855 if (VirtualState* states = virtual_states_[id]) {
856 if (std::find(object_states.begin(), object_states.end(), states) ==
857 object_states.end()) {
858 object_states.push_back(states);
859 }
860 }
861 }
862 for (size_t n = 0; n < object_states.size(); n++) {
863 PrintF("Dumping object state %p\n", static_cast<void*>(object_states[n]));
864 for (size_t id = 0; id < object_states[n]->size(); id++) {
865 if (VirtualObject* obj = object_states[n]->GetVirtualObject(id)) {
866 if (obj->id() == id) {
867 PrintF(" Object #%zu with %zu fields", id, obj->fields());
868 if (Node* rep = obj->GetReplacement()) {
869 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic());
870 }
871 PrintF("\n");
872 for (size_t i = 0; i < obj->fields(); ++i) {
873 if (Node* f = obj->GetField(i)) {
874 PrintF(" Field %zu = #%d (%s)\n", i, f->id(),
875 f->op()->mnemonic());
876 }
877 }
878 } else {
879 PrintF(" Object #%zu links to object #%d\n", id, obj->id());
880 }
881 }
882 }
883 }
884 }
885
886 } // namespace compiler
887 } // namespace internal
888 } // 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