OLD | NEW |
---|---|
(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 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | |
25 bool changed = status_ != other.status_; | |
26 status_ = other.status_; | |
27 changed = representation_ != other.representation_ || changed; | |
28 representation_ = other.representation_; | |
29 if (fields_.size() != other.fields_.size()) { | |
30 fields_ = other.fields_; | |
31 return true; | |
32 } | |
33 for (size_t i = 0; i < fields_.size(); ++i) { | |
34 if (fields_[i] != other.fields_[i]) { | |
35 changed = true; | |
36 fields_[i] = other.fields_[i]; | |
37 } | |
38 } | |
39 return changed; | |
40 } | |
41 | |
42 | |
43 VirtualState::VirtualState(Zone* zone, size_t size) | |
44 : info_(zone), last_changed_(nullptr) { | |
45 info_.resize(size); | |
46 } | |
47 | |
48 | |
49 VirtualState::VirtualState(const VirtualState& states) | |
50 : info_(states.info_.get_allocator().zone()), | |
51 last_changed_(states.last_changed_) { | |
52 info_.resize(states.info_.size()); | |
53 for (size_t i = 0; i < states.info_.size(); ++i) { | |
54 if (states.info_[i] && states.info_[i]->id() == i) { | |
55 info_[i] = new (states.info_.get_allocator().zone()) | |
56 VirtualObject(*states.info_[i]); | |
57 } | |
58 } | |
59 for (size_t i = 0; i < states.info_.size(); ++i) { | |
60 if (states.info_[i] && states.info_[i]->id() != i) { | |
61 info_[i] = info_[states.info_[i]->id()]; | |
62 } | |
63 } | |
64 } | |
65 | |
66 | |
67 VirtualObject* VirtualState::GetState(size_t id) { return info_[id]; } | |
68 | |
69 | |
70 VirtualObject* VirtualState::GetState(Node* node) { | |
71 return GetState(node->id()); | |
72 } | |
73 | |
74 | |
75 void VirtualState::SetState(NodeId id, VirtualObject* state) { | |
76 info_[id] = state; | |
77 } | |
78 | |
79 | |
80 bool VirtualState::UpdateFrom(NodeId id, VirtualObject* new_state, Zone* zone) { | |
81 VirtualObject* state = GetState(id); | |
82 if (!state) { | |
83 state = new (zone) VirtualObject(*new_state); | |
84 SetState(id, state); | |
85 if (FLAG_trace_turbo_escape) { | |
86 PrintF(" Taking field for #%d from %p\n", id, | |
87 static_cast<void*>(new_state)); | |
88 } | |
89 return true; | |
90 } | |
91 | |
92 if (state->UpdateFrom(*new_state)) { | |
93 if (FLAG_trace_turbo_escape) { | |
94 PrintF(" Updating field for #%d from %p\n", id, | |
95 static_cast<void*>(new_state)); | |
96 } | |
97 return true; | |
98 } | |
99 | |
100 return false; | |
101 } | |
102 | |
103 | |
104 // ------------------------------EscapeStatusAnalysis--------------------------- | |
105 | |
106 | |
107 EscapeStatusAnalysis::EscapeStatusAnalysis(Graph* graph, Zone* zone) | |
108 : graph_(graph), zone_(zone), info_(zone), queue_(zone) { | |
109 info_.resize(graph->NodeCount()); | |
110 } | |
111 | |
112 | |
113 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | |
114 | |
115 | |
116 bool EscapeStatusAnalysis::HasEntry(Node* node) { | |
117 return info_[node->id()] != kUnknown; | |
118 } | |
119 | |
120 | |
121 bool EscapeStatusAnalysis::IsVirtual(Node* node) { | |
122 if (node->id() >= info_.size()) { | |
123 return false; | |
124 } | |
125 return info_[node->id()] == kVirtual; | |
126 } | |
127 | |
128 | |
129 bool EscapeStatusAnalysis::IsEscaped(Node* node) { | |
130 return info_[node->id()] == kEscaped; | |
131 } | |
132 | |
133 | |
134 bool EscapeStatusAnalysis::SetEscaped(Node* node) { | |
135 bool changed = info_[node->id()] != kEscaped; | |
136 info_[node->id()] = kEscaped; | |
137 return changed; | |
138 } | |
139 | |
140 | |
141 void EscapeStatusAnalysis::Run() { | |
142 ZoneVector<bool> visited(zone()); | |
143 visited.resize(graph()->NodeCount()); | |
144 queue_.push_back(graph()->end()); | |
145 while (!queue_.empty()) { | |
146 Node* node = queue_.front(); | |
147 queue_.pop_front(); | |
148 Process(node); | |
149 if (!visited[node->id()]) { | |
150 RevisitInputs(node); | |
151 } | |
152 visited[node->id()] = true; | |
153 } | |
154 if (FLAG_trace_turbo_escape) { | |
155 DebugPrint(); | |
156 } | |
157 } | |
158 | |
159 | |
160 void EscapeStatusAnalysis::RevisitInputs(Node* node) { | |
161 for (Edge edge : node->input_edges()) { | |
162 Node* input = edge.to(); | |
163 queue_.push_back(input); | |
164 } | |
165 } | |
166 | |
167 | |
168 void EscapeStatusAnalysis::RevisitUses(Node* node) { | |
169 for (Edge edge : node->use_edges()) { | |
170 Node* use = edge.from(); | |
171 queue_.push_back(use); | |
172 } | |
173 } | |
174 | |
175 | |
176 void EscapeStatusAnalysis::Process(Node* node) { | |
177 switch (node->opcode()) { | |
178 case IrOpcode::kAllocate: | |
179 ProcessAllocate(node); | |
180 break; | |
181 case IrOpcode::kFinishRegion: | |
182 ProcessFinishRegion(node); | |
183 break; | |
184 case IrOpcode::kStoreField: | |
185 ProcessStoreField(node); | |
186 break; | |
187 case IrOpcode::kPhi: | |
188 if (!HasEntry(node)) { | |
189 info_[node->id()] = kVirtual; | |
190 } | |
191 CheckUsesForEscape(node); | |
192 default: | |
193 break; | |
194 } | |
195 } | |
196 | |
197 | |
198 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { | |
199 Node* to = NodeProperties::GetValueInput(node, 0); | |
200 Node* val = NodeProperties::GetValueInput(node, 1); | |
201 if (IsEscaped(to) && SetEscaped(val)) { | |
202 RevisitUses(val); | |
203 if (FLAG_trace_turbo_escape) { | |
204 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", | |
205 val->id(), val->op()->mnemonic(), to->id()); | |
206 } | |
207 } | |
208 } | |
209 | |
210 | |
211 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | |
212 DCHECK(node->opcode() == IrOpcode::kAllocate); | |
213 if (!HasEntry(node)) { | |
214 info_[node->id()] = kVirtual; | |
215 if (FLAG_trace_turbo_escape) { | |
216 PrintF("Created status entry for node #%d (%s)\n", node->id(), | |
217 node->op()->mnemonic()); | |
218 } | |
219 NumberMatcher size(node->InputAt(0)); | |
220 if (!size.HasValue() && SetEscaped(node)) { | |
221 RevisitUses(node); | |
222 if (FLAG_trace_turbo_escape) { | |
223 PrintF("Setting #%d to escaped because of non-const alloc\n", | |
224 node->id()); | |
225 } | |
226 // This node is known to escape, uses do not have to be checked. | |
227 return; | |
228 } | |
229 } | |
230 if (CheckUsesForEscape(node)) { | |
231 RevisitUses(node); | |
232 } | |
233 } | |
234 | |
235 | |
236 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* node) { | |
237 DCHECK(HasEntry(node)); | |
238 | |
239 for (Edge edge : node->use_edges()) { | |
240 Node* use = edge.from(); | |
241 if (!NodeProperties::IsValueEdge(edge)) continue; | |
242 switch (use->opcode()) { | |
243 case IrOpcode::kStoreField: | |
244 case IrOpcode::kLoadField: | |
245 case IrOpcode::kFrameState: | |
246 case IrOpcode::kStateValues: | |
247 case IrOpcode::kReferenceEqual: | |
248 case IrOpcode::kFinishRegion: | |
249 case IrOpcode::kPhi: | |
250 if (HasEntry(use) && IsEscaped(use) && SetEscaped(node)) { | |
251 if (FLAG_trace_turbo_escape) { | |
252 PrintF( | |
253 "Setting #%d (%s) to escaped because of use by escaping node " | |
254 "#%d (%s)\n", | |
255 node->id(), node->op()->mnemonic(), use->id(), | |
256 use->op()->mnemonic()); | |
257 } | |
258 return true; | |
259 } | |
260 break; | |
261 default: | |
262 if (SetEscaped(node)) { | |
263 if (FLAG_trace_turbo_escape) { | |
264 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | |
265 node->id(), node->op()->mnemonic(), use->id(), | |
266 use->op()->mnemonic()); | |
267 } | |
268 return true; | |
269 } | |
270 if (use->op()->EffectInputCount() == 0 && | |
271 node->op()->EffectInputCount() > 0) { | |
272 if (FLAG_trace_turbo_escape) { | |
273 PrintF("Encountered unaccounted use by #%d (%s)\n", use->id(), | |
274 use->op()->mnemonic()); | |
275 } | |
276 UNREACHABLE(); | |
277 } | |
278 } | |
279 } | |
280 return false; | |
281 } | |
282 | |
283 | |
284 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | |
285 DCHECK(node->opcode() == IrOpcode::kFinishRegion); | |
286 if (!HasEntry(node)) { | |
287 info_[node->id()] = kVirtual; | |
288 RevisitUses(node); | |
289 } | |
290 if (CheckUsesForEscape(node)) { | |
291 RevisitInputs(node); | |
292 } | |
293 } | |
294 | |
295 | |
296 void EscapeStatusAnalysis::DebugPrint() { | |
297 for (NodeId id = 0; id < info_.size(); id++) { | |
298 if (info_[id] != kUnknown) { | |
299 PrintF("Node #%d is %s\n", id, | |
300 info_[id] == kEscaped ? "escaping" : "virtual"); | |
301 } | |
302 } | |
303 } | |
304 | |
305 | |
306 // -----------------------------EscapeVirtualAnalysis--------------------------- | |
Michael Starzinger
2015/11/30 10:05:39
nit: s/EscapeVirtualAnalysis/EscapeObjectAnalysis/
sigurds
2015/11/30 13:50:23
Done.
| |
307 | |
308 | |
309 EscapeObjectAnalysis::EscapeObjectAnalysis(Graph* graph, | |
310 CommonOperatorBuilder* common, | |
311 Zone* zone) | |
312 : graph_(graph), common_(common), zone_(zone), states_(zone) { | |
313 states_.resize(graph->NodeCount()); | |
314 } | |
315 | |
316 | |
317 EscapeObjectAnalysis::~EscapeObjectAnalysis() {} | |
318 | |
319 | |
320 void EscapeObjectAnalysis::Run() { | |
321 ZoneVector<Node*> queue_(zone()); | |
322 queue_.push_back(graph()->start()); | |
323 while (!queue_.empty()) { | |
324 Node* node = queue_.back(); | |
325 queue_.pop_back(); | |
326 if (Process(node)) { | |
327 for (Edge edge : node->use_edges()) { | |
328 if (NodeProperties::IsEffectEdge(edge)) { | |
329 Node* use = edge.from(); | |
330 if (use->opcode() != IrOpcode::kLoadField || | |
331 !IsDanglingEffectNode(use)) { | |
332 queue_.push_back(use); | |
333 } | |
334 } | |
335 } | |
336 // First process loads: dangling loads are a problem otherwise. | |
337 for (Edge edge : node->use_edges()) { | |
338 if (NodeProperties::IsEffectEdge(edge)) { | |
339 Node* use = edge.from(); | |
340 if (use->opcode() == IrOpcode::kLoadField && | |
341 IsDanglingEffectNode(use)) { | |
342 queue_.push_back(use); | |
343 } | |
344 } | |
345 } | |
346 } | |
347 } | |
348 if (FLAG_trace_turbo_escape) { | |
349 DebugPrint(); | |
350 } | |
351 } | |
352 | |
353 | |
354 bool EscapeObjectAnalysis::IsDanglingEffectNode(Node* node) { | |
355 if (node->op()->EffectInputCount() == 0) return false; | |
356 if (node->op()->EffectOutputCount() == 0) return false; | |
357 for (Edge edge : node->use_edges()) { | |
358 if (NodeProperties::IsEffectEdge(edge)) { | |
359 return false; | |
360 } | |
361 } | |
362 return true; | |
363 } | |
364 | |
365 | |
366 bool EscapeObjectAnalysis::Process(Node* node) { | |
367 switch (node->opcode()) { | |
368 case IrOpcode::kAllocate: | |
369 ProcessAllocation(node); | |
370 break; | |
371 case IrOpcode::kBeginRegion: | |
372 ForwardObjectState(node); | |
373 break; | |
374 case IrOpcode::kFinishRegion: | |
375 ProcessFinishRegion(node); | |
376 break; | |
377 case IrOpcode::kStoreField: | |
378 ProcessStoreField(node); | |
379 break; | |
380 case IrOpcode::kLoadField: | |
381 ProcessLoadField(node); | |
382 break; | |
383 case IrOpcode::kStart: | |
384 ProcessStart(node); | |
385 break; | |
386 case IrOpcode::kEffectPhi: | |
387 return ProcessEffectPhi(node); | |
388 break; | |
389 default: | |
390 if (node->op()->EffectInputCount() > 0) { | |
391 ForwardObjectState(node); | |
392 } | |
393 break; | |
394 } | |
395 return true; | |
396 } | |
397 | |
398 | |
399 bool EscapeObjectAnalysis::IsEffectBranchPoint(Node* node) { | |
400 int count = 0; | |
401 for (Edge edge : node->use_edges()) { | |
402 Node* use = edge.from(); | |
403 if (NodeProperties::IsEffectEdge(edge) && | |
404 use->opcode() != IrOpcode::kLoadField) { | |
405 ++count; | |
406 } | |
407 } | |
408 return count > 1; | |
409 } | |
410 | |
411 | |
412 void EscapeObjectAnalysis::ForwardObjectState(Node* node) { | |
413 DCHECK(node->op()->EffectInputCount() == 1); | |
414 if (node->opcode() != IrOpcode::kLoadField && IsDanglingEffectNode(node)) { | |
415 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | |
416 node->op()->mnemonic()); | |
417 DCHECK(false); | |
418 } | |
419 Node* effect = NodeProperties::GetEffectInput(node); | |
420 // Break the cycle for effect phis. | |
421 if (effect->opcode() == IrOpcode::kEffectPhi) { | |
422 if (states_[effect->id()] == nullptr) { | |
423 states_[effect->id()] = | |
424 new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
425 } | |
426 } | |
427 DCHECK_NOT_NULL(states_[effect->id()]); | |
428 if (IsEffectBranchPoint(effect)) { | |
429 if (states_[node->id()]) return; | |
430 states_[node->id()] = new (zone()) VirtualState(*states_[effect->id()]); | |
431 if (FLAG_trace_turbo_escape) { | |
432 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | |
433 static_cast<void*>(states_[effect->id()]), effect->id(), | |
434 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | |
435 } | |
436 } else { | |
437 states_[node->id()] = states_[effect->id()]; | |
438 if (FLAG_trace_turbo_escape) { | |
439 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | |
440 static_cast<void*>(states_[effect->id()]), effect->id(), | |
441 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | |
442 } | |
443 } | |
444 } | |
445 | |
446 | |
447 void EscapeObjectAnalysis::ProcessStart(Node* node) { | |
448 states_[node->id()] = new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
449 } | |
450 | |
451 | |
452 bool EscapeObjectAnalysis::ProcessEffectPhi(Node* node) { | |
453 // For now only support binary phis. | |
454 DCHECK_EQ(node->op()->EffectInputCount(), 2); | |
455 Node* left = NodeProperties::GetEffectInput(node, 0); | |
456 Node* right = NodeProperties::GetEffectInput(node, 1); | |
457 bool changed = false; | |
458 | |
459 VirtualState* merge = states_[node->id()]; | |
460 if (!merge) { | |
461 merge = new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
462 states_[node->id()] = merge; | |
463 changed = true; | |
464 if (FLAG_trace_turbo_escape) { | |
465 PrintF("Phi #%d got new states map %p.\n", node->id(), | |
466 static_cast<void*>(merge)); | |
467 } | |
468 } else if (merge->GetLastChanged() != node) { | |
469 changed = true; | |
470 } | |
471 VirtualState* l = states_[left->id()]; | |
472 VirtualState* r = states_[right->id()]; | |
473 | |
474 if (FLAG_trace_turbo_escape) { | |
475 PrintF("At Phi #%d, merging states %p and %p\n", node->id(), | |
476 static_cast<void*>(l), static_cast<void*>(r)); | |
477 } | |
478 | |
479 for (NodeId id = 0; id < states_.size(); ++id) { | |
480 VirtualObject* ls = l ? l->GetState(id) : nullptr; | |
481 VirtualObject* rs = r ? r->GetState(id) : nullptr; | |
482 VirtualObject* state = merge->GetState(id); | |
483 | |
484 if (ls != nullptr && rs != nullptr) { | |
485 if (FLAG_trace_turbo_escape) { | |
486 PrintF(" Merging fields of #%d\n", id); | |
487 } | |
488 size_t fields = std::max(ls->fields(), rs->fields()); | |
489 | |
490 if (!state) { | |
491 state = new (zone()) VirtualObject(id, zone(), fields); | |
492 merge->SetState(id, state); | |
493 changed = true; | |
494 } | |
495 for (size_t i = 0; i < fields; ++i) { | |
496 if (ls->GetField(i) == rs->GetField(i)) { | |
497 changed = state->SetField(i, ls->GetField(i)) || changed; | |
498 if (FLAG_trace_turbo_escape && ls->GetField(i)) { | |
499 PrintF(" Field %zu agree on rep #%d\n", i, | |
500 ls->GetField(i)->id()); | |
501 } | |
502 } else { | |
503 Node* phi = graph()->NewNode(common()->Phi(kMachAnyTagged, 2), | |
504 ls->GetField(i), rs->GetField(i), | |
505 NodeProperties::GetControlInput(node)); | |
506 if (state->SetField(i, phi)) { | |
507 if (FLAG_trace_turbo_escape) { | |
508 PrintF(" Creating Phi #%d as merge of #%d and #%d\n", | |
509 phi->id(), ls->GetField(i)->id(), rs->GetField(i)->id()); | |
510 } | |
511 changed = true; | |
512 } | |
513 } | |
514 } | |
515 } else if (ls != nullptr) { | |
516 changed = merge->UpdateFrom(id, ls, zone()) || changed; | |
517 } else if (rs != nullptr) { | |
518 changed = merge->UpdateFrom(id, rs, zone()) || changed; | |
519 } | |
520 } | |
521 if (FLAG_trace_turbo_escape) { | |
522 PrintF("Merge %s the node.\n", changed ? "changed" : "did not change"); | |
523 } | |
524 if (changed) { | |
525 merge->SetLastChanged(node); | |
526 } | |
527 return changed; | |
528 } | |
529 | |
530 | |
531 void EscapeObjectAnalysis::ProcessAllocation(Node* node) { | |
532 ForwardObjectState(node); | |
533 | |
534 // Check if we have already processed this node. | |
535 if (states_[node->id()]->GetState(node)) return; | |
536 | |
537 NumberMatcher size(node->InputAt(0)); | |
538 if (size.HasValue()) { | |
539 states_[node->id()]->SetState( | |
540 node->id(), | |
541 new (zone()) VirtualObject(node->id(), zone(), size.Value())); | |
542 } else { | |
543 states_[node->id()]->SetState( | |
544 node->id(), new (zone()) VirtualObject(node->id(), zone())); | |
545 } | |
546 states_[node->id()]->SetLastChanged(node); | |
547 } | |
548 | |
549 | |
550 void EscapeObjectAnalysis::ProcessFinishRegion(Node* node) { | |
551 ForwardObjectState(node); | |
552 Node* allocation = NodeProperties::GetValueInput(node, 0); | |
553 if (allocation->opcode() == IrOpcode::kAllocate) { | |
554 VirtualState* states = states_[node->id()]; | |
555 DCHECK_NOT_NULL(states->GetState(allocation)); | |
556 if (!states->GetState(node->id())) { | |
557 states->SetState(node->id(), states->GetState(allocation)); | |
558 if (FLAG_trace_turbo_escape) { | |
559 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | |
560 allocation->id()); | |
561 } | |
562 states->SetLastChanged(node); | |
563 } | |
564 } | |
565 } | |
566 | |
567 | |
568 Node* EscapeObjectAnalysis::representation(Node* at, NodeId id) { | |
569 VirtualState* states = states_[at->id()]; | |
570 if (VirtualObject* state = states->GetState(id)) { | |
571 return state->GetRepresentation(); | |
572 } | |
573 return nullptr; | |
574 } | |
575 | |
576 | |
577 void EscapeObjectAnalysis::ProcessLoadField(Node* node) { | |
578 ForwardObjectState(node); | |
579 Node* from = NodeProperties::GetValueInput(node, 0); | |
580 int offset = OpParameter<FieldAccess>(node).offset; | |
581 VirtualState* states = states_[node->id()]; | |
582 if (VirtualObject* state = states->GetState(from)) { | |
583 if (!state->IsTracked()) return; | |
584 Node* value = state->GetField(offset); | |
585 if (value) { | |
586 // Record that the load has has this alias. | |
587 if (!states->GetState(node)) { | |
588 states->SetState(node->id(), | |
589 new (zone()) VirtualObject(node->id(), zone())); | |
590 } | |
591 if (states->GetState(node)->SetRepresentation(value)) { | |
592 states->SetLastChanged(node); | |
593 if (FLAG_trace_turbo_escape) { | |
594 PrintF("Representation of #%d is #%d (%s)\n", node->id(), value->id(), | |
595 value->op()->mnemonic()); | |
596 } | |
597 } | |
598 } else if (FLAG_trace_turbo_escape) { | |
599 PrintF("No field %d on record for #%d\n", offset, from->id()); | |
600 } | |
601 } else { | |
602 if (from->opcode() == IrOpcode::kPhi) { | |
603 // Only binary phis are supported for now. | |
604 DCHECK_EQ(from->op()->ValueInputCount(), 2); | |
605 if (FLAG_trace_turbo_escape) { | |
606 PrintF("Load #%d from phi #%d", node->id(), from->id()); | |
607 } | |
608 Node* left = NodeProperties::GetValueInput(from, 0); | |
609 Node* right = NodeProperties::GetValueInput(from, 1); | |
610 VirtualObject* l = states->GetState(left); | |
611 VirtualObject* r = states->GetState(right); | |
612 if (l && r) { | |
613 Node* lv = l->GetField(offset); | |
614 Node* rv = r->GetField(offset); | |
615 if (lv && rv) { | |
616 if (!states->GetState(node)) { | |
617 states->SetState(node->id(), | |
618 new (zone()) VirtualObject(node->id(), zone())); | |
619 } | |
620 Node* rep = states->GetState(node)->GetRepresentation(); | |
621 if (!rep || rep->opcode() != IrOpcode::kPhi || | |
622 NodeProperties::GetValueInput(rep, 0) != lv || | |
623 NodeProperties::GetValueInput(rep, 1) != rv) { | |
624 Node* phi = | |
625 graph()->NewNode(common()->Phi(kMachAnyTagged, 2), lv, rv, | |
626 NodeProperties::GetControlInput(from)); | |
627 states->GetState(node)->SetRepresentation(phi); | |
628 states->SetLastChanged(node); | |
629 if (FLAG_trace_turbo_escape) { | |
630 PrintF(" got phi of #%d is #%d created.\n", lv->id(), rv->id()); | |
631 } | |
632 } else if (FLAG_trace_turbo_escape) { | |
633 PrintF(" has already the right phi representation.\n"); | |
634 } | |
635 } else if (FLAG_trace_turbo_escape) { | |
636 PrintF(" has incomplete field info: %p %p\n", static_cast<void*>(lv), | |
637 static_cast<void*>(rv)); | |
638 } | |
639 } else if (FLAG_trace_turbo_escape) { | |
640 PrintF(" has incomplete state info: %p %p\n", static_cast<void*>(l), | |
641 static_cast<void*>(r)); | |
642 } | |
643 } | |
644 } | |
645 } | |
646 | |
647 | |
648 void EscapeObjectAnalysis::ProcessStoreField(Node* node) { | |
649 ForwardObjectState(node); | |
650 Node* to = NodeProperties::GetValueInput(node, 0); | |
651 Node* val = NodeProperties::GetValueInput(node, 1); | |
652 int offset = OpParameter<FieldAccess>(node).offset; | |
653 VirtualState* states = states_[node->id()]; | |
654 if (VirtualObject* state = states->GetState(to)) { | |
655 if (!state->IsTracked()) return; | |
656 Node* resolved_value = val; | |
657 if (states->GetState(val)) { | |
658 if (Node* rep = states->GetState(val)->GetRepresentation()) { | |
659 resolved_value = rep; | |
660 } | |
661 } | |
662 if (state->SetField(offset, resolved_value)) { | |
663 states->SetLastChanged(node); | |
664 } | |
665 } | |
666 } | |
667 | |
668 | |
669 void EscapeObjectAnalysis::DebugPrint() { | |
670 ZoneVector<VirtualState*> object_states(zone()); | |
671 for (NodeId id = 0; id < states_.size(); id++) { | |
672 if (VirtualState* states = states_[id]) { | |
673 if (std::find(object_states.begin(), object_states.end(), states) == | |
674 object_states.end()) { | |
675 object_states.push_back(states); | |
676 } | |
677 } | |
678 } | |
679 for (size_t n = 0; n < object_states.size(); n++) { | |
680 PrintF("Dumping object state %p\n", static_cast<void*>(object_states[n])); | |
681 for (size_t id = 0; id < object_states[n]->size(); id++) { | |
682 if (VirtualObject* obj = object_states[n]->GetState(id)) { | |
683 if (obj->id() == id) { | |
684 PrintF(" Object #%zu with %zu fields", id, obj->fields()); | |
685 if (Node* rep = obj->GetRepresentation()) { | |
686 PrintF(", rep = #%d (%s)", rep->id(), rep->op()->mnemonic()); | |
687 } | |
688 PrintF("\n"); | |
689 for (size_t i = 0; i < obj->fields(); ++i) { | |
690 if (Node* f = obj->GetField(i)) { | |
691 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), | |
692 f->op()->mnemonic()); | |
693 } | |
694 } | |
695 } else { | |
696 PrintF(" Object #%zu links to object #%d\n", id, obj->id()); | |
697 } | |
698 } | |
699 } | |
700 } | |
701 } | |
702 | |
703 } // namespace compiler | |
704 } // namespace internal | |
705 } // namespace v8 | |
OLD | NEW |